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

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

pub fn build_order_payload(intent: &OrderIntent, nonce: u64) -> 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(
        "hyperliquid_order",
        &[
            ("nonce", json!(nonce)),
            ("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 builds_hyperliquid_payload() {
        let mut intent = OrderIntent::new(
            "acct",
            ExecutionVenue::Hyperliquid,
            InstrumentType::Perp,
            "BTC",
            "BTC-PERP",
            OrderSide::Buy,
            OrderType::Limit,
            1.0,
        );
        intent.price = Some(100_000.0);
        let payload = build_order_payload(&intent, 7).expect("payload");
        assert_eq!(payload["nonce"], 7);
        assert_eq!(payload["symbol"], "BTC-PERP");
    }
}
