//! TFT model integration test
//!
//! Verifies: sequence buffering -> forward pass -> quantile output
//! TFT requires sequence_length observations before producing real predictions.
//! Uses lightweight config for fast execution (<10s)

use ml::ensemble::adapters::TftInferenceAdapter;
use ml::ensemble::inference_adapter::{FeatureVector, ModelInferenceAdapter};
use ml::tft::TFTConfig;

fn small_tft_config() -> TFTConfig {
    TFTConfig {
        input_dim: 20,
        hidden_dim: 32,
        num_heads: 2,
        num_layers: 1,
        prediction_horizon: 5,
        sequence_length: 4,
        num_quantiles: 9,
        num_static_features: 6,
        num_known_features: 6,
        num_unknown_features: 8,
        dropout_rate: 0.0,
        ..Default::default()
    }
}

const SEQ_LEN: usize = 4;

fn make_fv(ts: i64) -> FeatureVector {
    FeatureVector {
        values: vec![0.1; 51],
        timestamp: ts,
    }
}

#[test]
fn test_tft_adapter_buffers_before_predicting() {
    let adapter = TftInferenceAdapter::new(small_tft_config(), SEQ_LEN)
        .expect("TftInferenceAdapter::new should succeed");

    assert_eq!(adapter.model_name(), "TFT");
    assert!(
        !adapter.is_ready(),
        "TFT should not be ready with empty buffer"
    );

    // Feed SEQ_LEN - 1 feature vectors: should return neutral (0.0, 0.0)
    for i in 0..(SEQ_LEN - 1) {
        let pred = adapter
            .predict(&make_fv(1_700_000_000 + i as i64))
            .expect("predict should not error during buffering");
        assert_eq!(
            pred.direction, 0.0,
            "Should return neutral direction while buffering"
        );
        assert_eq!(
            pred.confidence, 0.0,
            "Should return zero confidence while buffering"
        );
    }

    assert!(!adapter.is_ready(), "TFT should still not be ready");
}

#[test]
fn test_tft_produces_valid_prediction_after_warmup() {
    let adapter = TftInferenceAdapter::new(small_tft_config(), SEQ_LEN)
        .expect("TftInferenceAdapter::new should succeed");

    // Fill buffer
    for i in 0..SEQ_LEN {
        let _ = adapter.predict(&make_fv(1_700_000_000 + i as i64));
    }

    assert!(
        adapter.is_ready(),
        "TFT should be ready after filling buffer"
    );

    // Next prediction should produce real values
    let pred = adapter
        .predict(&make_fv(1_700_000_000 + SEQ_LEN as i64))
        .expect("TFT predict should succeed after warmup");

    assert!(
        pred.direction >= -1.0 && pred.direction <= 1.0,
        "direction {} out of [-1,1]",
        pred.direction
    );
    assert!(
        pred.confidence >= 0.0 && pred.confidence <= 1.0,
        "confidence {} out of [0,1]",
        pred.confidence
    );
    assert!(pred.direction.is_finite(), "direction must not be NaN/Inf");
    assert!(
        pred.confidence.is_finite(),
        "confidence must not be NaN/Inf"
    );
}
