use std::collections::HashSet;

use bt_kernel::{AssetClass, SymbolId, SymbolInfo, TimeRange, Timestamp};

#[test]
fn timestamp_order_hash_and_eq_work() {
    let ts_a = Timestamp::from_nanos(10);
    let ts_b = Timestamp::from_nanos(20);

    assert!(ts_a < ts_b);
    assert_eq!(ts_a, Timestamp::from_nanos(10));

    let mut set = HashSet::new();
    set.insert(ts_a);
    set.insert(ts_b);
    set.insert(Timestamp::from_nanos(10));

    assert_eq!(set.len(), 2);
}

#[test]
fn symbol_id_order_hash_and_eq_work() {
    let id_a = SymbolId(1);
    let id_b = SymbolId(2);

    assert_ne!(id_a, id_b);

    let mut set = HashSet::new();
    set.insert(id_a);
    set.insert(id_b);
    set.insert(SymbolId(1));

    assert_eq!(set.len(), 2);
}

#[test]
fn time_range_validates_start_before_end() {
    assert!(TimeRange::new(Timestamp(0), Timestamp(1)).is_ok());
    assert!(TimeRange::new(Timestamp(1), Timestamp(1)).is_err());
    assert!(TimeRange::new(Timestamp(2), Timestamp(1)).is_err());
}

#[test]
fn serde_roundtrip_for_kernel_types() {
    let info = SymbolInfo {
        id: SymbolId(42),
        ticker: "BTCUSDT".to_string(),
        asset_class: AssetClass::CryptoSpot,
        exchange: "BINANCE".to_string(),
        base_currency: "BTC".to_string(),
        quote_currency: "USDT".to_string(),
        tick_size: 0.01,
        lot_size: 0.0001,
        margin_required: None,
    };

    let json = serde_json::to_string(&info).expect("serialize symbol info");
    let decoded: SymbolInfo = serde_json::from_str(&json).expect("deserialize symbol info");

    assert_eq!(decoded, info);

    let range = TimeRange::new(Timestamp(1_000_000_000), Timestamp(2_000_000_000))
        .expect("valid time range");
    let range_json = serde_json::to_string(&range).expect("serialize time range");
    let range_decoded: TimeRange =
        serde_json::from_str(&range_json).expect("deserialize time range");

    assert_eq!(range_decoded, range);
}
