use serde_json::json;
use std::collections::HashMap;
use uforia_execution_core::{
    dry_run_payload, ExecutionError, ExecutionVenue, InstrumentType, OrderIntent, OrderType,
    VenueCapabilities,
};

pub fn capabilities() -> VenueCapabilities {
    VenueCapabilities {
        venue: ExecutionVenue::Derive,
        instrument_types: vec![InstrumentType::Option, InstrumentType::Perp],
        order_types: vec![
            OrderType::Market,
            OrderType::Limit,
            OrderType::PostOnlyLimit,
            OrderType::Ioc,
            OrderType::ReduceOnlyLimit,
        ],
        supports_post_only: true,
        supports_reduce_only: true,
        supports_amend: true,
        supports_mass_cancel: true,
        supports_private_ws: true,
        supports_quote_routing: false,
    }
}

pub fn build_session_headers(api_key: &str, session_key: &str) -> HashMap<String, String> {
    HashMap::from([
        ("x-derive-api-key".to_string(), api_key.to_string()),
        ("x-derive-session".to_string(), session_key.to_string()),
    ])
}

pub fn build_order_payload(intent: &OrderIntent) -> Result<serde_json::Value, ExecutionError> {
    let caps = capabilities();
    if !caps.instrument_types.contains(&intent.instrument_type) {
        return Err(ExecutionError::UnsupportedInstrumentType);
    }
    if !caps.order_types.contains(&intent.order_type) {
        return Err(ExecutionError::UnsupportedOrderType);
    }
    Ok(dry_run_payload(
        "derive_order",
        &[
            ("symbol", json!(intent.symbol)),
            ("side", json!(intent.side)),
            ("order_type", json!(intent.order_type)),
            ("time_in_force", json!(intent.time_in_force)),
            ("price", json!(intent.price)),
            ("size", json!(intent.size)),
            ("reduce_only", json!(intent.reduce_only)),
        ],
    ))
}

#[cfg(test)]
mod tests {
    use super::*;
    use uforia_execution_core::{ExecutionVenue, InstrumentType, OrderIntent, OrderSide};

    #[test]
    fn derive_headers_are_named() {
        let headers = build_session_headers("k", "s");
        assert_eq!(headers.get("x-derive-api-key"), Some(&"k".to_string()));
    }

    #[test]
    fn derive_builds_option_payload() {
        let mut intent = OrderIntent::new(
            "acct",
            ExecutionVenue::Derive,
            InstrumentType::Option,
            "BTC",
            "BTC-29MAR24-50000-C",
            OrderSide::Buy,
            OrderType::Limit,
            1.0,
        );
        intent.price = Some(1_000.0);
        let payload = build_order_payload(&intent).expect("payload");
        assert_eq!(payload["symbol"], "BTC-29MAR24-50000-C");
    }
}
