use chrono::Utc;
use market_data::models::{
    BookSide, IndicatorType, OrderBook, OrderBookLevelDb, PriceRecord, TechnicalIndicator,
};
use rust_decimal_macros::dec;
use std::collections::HashMap;

#[test]
fn test_price_model() {
    let mut price = PriceRecord::new("EURUSD".to_string(), Utc::now());
    price.bid = Some(dec!(1.0850));
    price.ask = Some(dec!(1.0852));

    let mid = price.mid_price();
    assert_eq!(mid, Some(dec!(1.0851)));

    let spread = price.spread();
    assert_eq!(spread, Some(dec!(0.0002)));
}

#[test]
fn test_order_book_model() {
    let mut order_book = OrderBook::new("EURUSD".to_string(), Utc::now());

    // Add some levels
    let bid_level = OrderBookLevelDb::new(
        "EURUSD".to_string(),
        Utc::now(),
        BookSide::Bid,
        dec!(1.0850),
        dec!(1000000),
        0,
    );

    let ask_level = OrderBookLevelDb::new(
        "EURUSD".to_string(),
        Utc::now(),
        BookSide::Ask,
        dec!(1.0852),
        dec!(1000000),
        0,
    );

    order_book.bids.push(bid_level);
    order_book.asks.push(ask_level);

    assert_eq!(order_book.best_bid(), Some(dec!(1.0850)));
    assert_eq!(order_book.best_ask(), Some(dec!(1.0852)));
    assert_eq!(order_book.mid_price(), Some(dec!(1.0851)));
    assert_eq!(order_book.spread(), Some(dec!(0.0002)));
}

#[test]
fn test_technical_indicator_model() {
    let indicator = TechnicalIndicator::new(
        "EURUSD".to_string(),
        IndicatorType::Sma,
        Utc::now(),
        dec!(1.0851),
        serde_json::json!({"period": 20}),
    );

    assert_eq!(indicator.symbol, "EURUSD");
    assert_eq!(indicator.indicator_type, IndicatorType::Sma);
    assert_eq!(indicator.value, dec!(1.0851));
}

#[test]
fn test_hash_traits() {
    // Test BookSide is hashable
    let mut side_map: HashMap<BookSide, i32> = HashMap::new();
    side_map.insert(BookSide::Bid, 1);
    side_map.insert(BookSide::Ask, 2);

    assert_eq!(side_map.get(&BookSide::Bid), Some(&1));
    assert_eq!(side_map.get(&BookSide::Ask), Some(&2));

    // Test IndicatorType is hashable
    let mut indicator_map: HashMap<IndicatorType, String> = HashMap::new();
    indicator_map.insert(IndicatorType::Sma, "SMA".to_string());
    indicator_map.insert(IndicatorType::Ema, "EMA".to_string());

    assert_eq!(
        indicator_map.get(&IndicatorType::Sma),
        Some(&"SMA".to_string())
    );
    assert_eq!(
        indicator_map.get(&IndicatorType::Ema),
        Some(&"EMA".to_string())
    );
}
