//! Integration tests for gap event emission and multi-symbol isolation (Issue #257).

use std::sync::Arc;
use tokio::sync::mpsc;

use opendeviationbar_streaming::gap::{GapEvent, TradeIdGapDetector};

#[test]
fn test_gap_event_emitted_on_channel() {
    // When a gap is detected, a GapEvent should be sent on the channel
    let (tx, mut rx) = mpsc::channel::<GapEvent>(16);
    let mut detector = TradeIdGapDetector::new(Arc::from("BTCUSDT"), Some(tx));

    detector.seed(100);
    let result = detector.check(105); // Gap of 4 trades (101-104 missing)

    assert!(result.is_some());
    let (last_id, gap_size) = result.unwrap();
    assert_eq!(last_id, 100);
    assert_eq!(gap_size, 4);

    // Event should be on the channel (non-blocking try_recv)
    let event = rx.try_recv().expect("should have received gap event");
    assert_eq!(&*event.symbol, "BTCUSDT");
    assert_eq!(event.expected_tid, 101);
    assert_eq!(event.actual_tid, 105);
    assert_eq!(event.gap_size, 4);
    assert!(!event.filled_inline);
}

#[test]
fn test_multi_symbol_isolation() {
    // Gap events from different symbols should be independently tracked
    let (tx, mut rx) = mpsc::channel::<GapEvent>(32);
    let mut btc_detector = TradeIdGapDetector::new(Arc::from("BTCUSDT"), Some(tx.clone()));
    let mut eth_detector = TradeIdGapDetector::new(Arc::from("ETHUSDT"), Some(tx));

    btc_detector.seed(1000);
    eth_detector.seed(2000);

    // BTC gap: 1001-1004 missing
    let btc_result = btc_detector.check(1005);
    assert!(btc_result.is_some());

    // ETH contiguous: no gap
    let eth_result = eth_detector.check(2001);
    assert!(eth_result.is_none());

    // ETH gap: 2002-2009 missing
    eth_detector.update_last_tid(2001);
    let eth_result = eth_detector.check(2010);
    assert!(eth_result.is_some());

    // Should have exactly 2 events: one BTC, one ETH
    let ev1 = rx.try_recv().expect("BTC gap event");
    assert_eq!(&*ev1.symbol, "BTCUSDT");
    assert_eq!(ev1.gap_size, 4);

    let ev2 = rx.try_recv().expect("ETH gap event");
    assert_eq!(&*ev2.symbol, "ETHUSDT");
    assert_eq!(ev2.gap_size, 8);

    // No more events
    assert!(rx.try_recv().is_err());
}

#[test]
fn test_gap_event_not_emitted_for_contiguous() {
    // No event should be emitted when trades are contiguous
    let (tx, mut rx) = mpsc::channel::<GapEvent>(16);
    let mut detector = TradeIdGapDetector::new(Arc::from("BTCUSDT"), Some(tx));

    detector.seed(100);
    assert!(detector.check(101).is_none());
    detector.update_last_tid(101);
    assert!(detector.check(102).is_none());

    assert!(rx.try_recv().is_err(), "no events for contiguous trades");
}

#[test]
fn test_gap_event_channel_full_does_not_block() {
    // When channel is full, gap detection should still work (try_send drops event)
    let (tx, _rx) = mpsc::channel::<GapEvent>(1); // capacity=1
    let mut detector = TradeIdGapDetector::new(Arc::from("BTCUSDT"), Some(tx));

    detector.seed(100);

    // First gap fills the channel
    assert!(detector.check(110).is_some());
    detector.update_last_tid(110);

    // Second gap should still detect even though channel is full
    let result = detector.check(120);
    assert!(result.is_some());
    assert_eq!(detector.gaps_detected(), 2);
}
