#![allow(
    clippy::assertions_on_constants,
    clippy::assertions_on_result_states,
    clippy::clone_on_copy,
    clippy::decimal_literal_representation,
    clippy::doc_markdown,
    clippy::empty_line_after_doc_comments,
    clippy::field_reassign_with_default,
    clippy::get_unwrap,
    clippy::identity_op,
    clippy::inconsistent_digit_grouping,
    clippy::indexing_slicing,
    clippy::integer_division,
    clippy::len_zero,
    clippy::let_underscore_must_use,
    clippy::manual_div_ceil,
    clippy::manual_let_else,
    clippy::manual_range_contains,
    clippy::modulo_arithmetic,
    clippy::needless_range_loop,
    clippy::non_ascii_literal,
    clippy::redundant_clone,
    clippy::shadow_reuse,
    clippy::shadow_same,
    clippy::shadow_unrelated,
    clippy::single_match_else,
    clippy::str_to_string,
    clippy::string_slice,
    clippy::tests_outside_test_module,
    clippy::too_many_lines,
    clippy::unnecessary_wraps,
    clippy::unseparated_literal_suffix,
    clippy::use_debug,
    clippy::useless_vec,
    clippy::wildcard_enum_match_arm,
    clippy::else_if_without_else,
    clippy::expect_used,
    clippy::missing_const_for_fn,
    clippy::similar_names,
    clippy::type_complexity,
    clippy::collapsible_else_if,
    clippy::doc_lazy_continuation,
    clippy::items_after_test_module,
    clippy::map_clone,
    clippy::multiple_unsafe_ops_per_block,
    clippy::unwrap_or_default,
    clippy::assign_op_pattern,
    clippy::needless_borrow,
    clippy::println_empty_string,
    clippy::unnecessary_cast,
    clippy::used_underscore_binding,
    clippy::create_dir,
    clippy::implicit_saturating_sub,
    clippy::exit,
    clippy::expect_fun_call,
    clippy::too_many_arguments,
    clippy::unnecessary_map_or,
    clippy::unwrap_used,
    dead_code,
    unused_imports,
    unused_variables,
    clippy::cloned_ref_to_slice_refs,
    clippy::neg_multiply,
    clippy::while_let_loop,
    clippy::bool_assert_comparison,
    clippy::excessive_precision,
    clippy::trivially_copy_pass_by_ref,
    clippy::op_ref,
    clippy::redundant_closure,
    clippy::unnecessary_lazy_evaluations,
    clippy::if_then_some_else_none,
    clippy::unnecessary_to_owned,
    clippy::single_component_path_imports,
)]
//! Temporal Fusion Transformer (TFT) Integration Tests
//!
//! Basic tests for TFT configuration and model creation.
#![allow(unused_crate_dependencies)]

use anyhow::Result;
use ml::tft::{TFTConfig, TFTState, TemporalFusionTransformer};
use tracing::warn;

mod real_data_helpers;
use real_data_helpers::{load_tft_sequences, real_data_available};

/// Test TFT configuration creation with default values
#[test]
fn test_tft_config_default() -> Result<()> {
    let config = TFTConfig::default();
    assert!(config.input_dim > 0);
    assert!(config.hidden_dim > 0);
    assert!(config.num_heads > 0);
    assert!(config.num_quantiles > 0);
    assert!(config.prediction_horizon > 0);
    assert!(config.sequence_length > 0);
    Ok(())
}

/// Test TFT configuration creation with custom values
#[test]
fn test_tft_config_custom() -> Result<()> {
    let config = TFTConfig {
        input_dim: 64,
        hidden_dim: 128,
        num_heads: 8,
        num_layers: 3,
        prediction_horizon: 10,
        sequence_length: 50,
        num_quantiles: 9,
        num_static_features: 5,
        num_known_features: 10,
        num_unknown_features: 49, // 5 + 10 + 49 = 64 (fixed feature count mismatch)
        learning_rate: 1e-3,
        batch_size: 64,
        dropout_rate: 0.1,
        l2_regularization: 1e-4,
        use_flash_attention: true,
        memory_efficient: true,
        max_inference_latency_us: 50,
        target_throughput_pps: 100_000,
    };

    assert_eq!(config.input_dim, 64);
    assert_eq!(config.hidden_dim, 128);
    assert_eq!(config.num_heads, 8);
    assert_eq!(config.num_quantiles, 9);
    Ok(())
}

/// Test TFT model creation
#[test]
fn test_tft_model_creation() -> Result<()> {
    let config = TFTConfig {
        input_dim: 10,
        hidden_dim: 32,
        num_heads: 4,
        num_quantiles: 5,
        prediction_horizon: 5,
        sequence_length: 20,
        num_static_features: 2,
        num_known_features: 3,
        num_unknown_features: 5,
        ..Default::default()
    };

    let tft = TemporalFusionTransformer::new(config)?;
    assert_eq!(tft.metadata.input_dim, 10);
    assert_eq!(tft.metadata.output_dim, 5);
    assert!(!tft.is_trained);
    Ok(())
}

/// Test TFT state creation
#[test]
fn test_tft_state_creation() -> Result<()> {
    let config = TFTConfig {
        hidden_dim: 32,
        sequence_length: 20,
        num_heads: 4,
        ..Default::default()
    };

    let state = TFTState::zeros(&config)?;
    assert_eq!(state.last_update, 0);
    assert!(state.attention_cache.is_empty());
    Ok(())
}

/// Test TFT performance metrics
#[test]
fn test_tft_performance_metrics() -> Result<()> {
    let config = TFTConfig {
        input_dim: 10,
        hidden_dim: 32,
        ..Default::default()
    };

    let tft = TemporalFusionTransformer::new(config)?;
    let metrics = tft.get_metrics();

    assert!(metrics.contains_key("total_inferences"));
    assert!(metrics.contains_key("avg_latency_us"));
    assert!(metrics.contains_key("max_latency_us"));
    assert!(metrics.contains_key("throughput_pps"));

    // Initial values should be zero
    assert_eq!(metrics["total_inferences"], 0.0);
    assert_eq!(metrics["avg_latency_us"], 0.0);
    Ok(())
}

/// Test TFT training state management
#[test]
fn test_tft_training_state() -> Result<()> {
    let config = TFTConfig::default();
    let mut tft = TemporalFusionTransformer::new(config)?;

    assert!(!tft.is_trained);
    tft.is_trained = true;
    assert!(tft.is_trained);
    Ok(())
}

/// Test TFT metadata
#[test]
fn test_tft_metadata() -> Result<()> {
    let config = TFTConfig {
        input_dim: 15,
        prediction_horizon: 12,
        ..Default::default()
    };

    let tft = TemporalFusionTransformer::new(config)?;
    assert_eq!(tft.metadata.input_dim, 15);
    assert_eq!(tft.metadata.output_dim, 12);
    assert_eq!(tft.metadata.version, "1.0.0");
    assert_eq!(tft.metadata.training_samples, 0);
    assert!(tft.metadata.last_trained.is_none());
    Ok(())
}

/// Test TFT configuration validation
#[test]
fn test_tft_config_validation() -> Result<()> {
    let config = TFTConfig {
        input_dim: 20,
        hidden_dim: 64,
        num_heads: 4,
        num_layers: 2,
        prediction_horizon: 10,
        sequence_length: 50,
        num_quantiles: 7,
        num_static_features: 3,
        num_known_features: 5,
        num_unknown_features: 12,
        learning_rate: 0.001,
        batch_size: 32,
        dropout_rate: 0.1,
        l2_regularization: 0.0001,
        use_flash_attention: false,
        memory_efficient: true,
        max_inference_latency_us: 100,
        target_throughput_pps: 50_000,
    };

    assert!(config.input_dim > 0);
    assert!(config.hidden_dim > 0);
    assert!(config.num_heads > 0);
    assert!(config.num_layers > 0);
    assert!(config.prediction_horizon > 0);
    assert!(config.sequence_length > 0);
    assert!(config.num_quantiles > 0);
    assert!(config.learning_rate > 0.0);
    assert!(config.batch_size > 0);
    assert!(config.dropout_rate >= 0.0 && config.dropout_rate < 1.0);
    assert!(config.max_inference_latency_us > 0);
    assert!(config.target_throughput_pps > 0);
    Ok(())
}

/// Test multiple TFT model configurations
#[test]
fn test_multiple_tft_configs() -> Result<()> {
    let configs = vec![
        TFTConfig {
            input_dim: 10,
            hidden_dim: 32,
            num_heads: 2,
            ..Default::default()
        },
        TFTConfig {
            input_dim: 20,
            hidden_dim: 64,
            num_heads: 4,
            ..Default::default()
        },
        TFTConfig {
            input_dim: 30,
            hidden_dim: 128,
            num_heads: 8,
            ..Default::default()
        },
    ];

    for config in configs {
        let tft = TemporalFusionTransformer::new(config)?;
        assert!(!tft.is_trained);
        assert!(tft.metadata.training_samples == 0);
    }
    Ok(())
}

// ============================================================================
// Real Market Data Tests
// ============================================================================

/// Test TFT model creation with real market data dimensions
#[tokio::test]
async fn test_tft_model_creation_real_data_dimensions() -> Result<()> {
    // Skip if no real data available
    if !real_data_available().await {
        warn!("Skipping test: real data not available");
        return Ok(());
    }

    // Load sample sequences to determine realistic dimensions
    let sequences = load_tft_sequences(10, 20, 10).await?;
    if sequences.is_empty() {
        warn!("Skipping test: no sequences loaded");
        return Ok(());
    }

    // Create TFT config matching real data dimensions
    let config = TFTConfig {
        input_dim: 10, // Features per timestep (OHLCV)
        hidden_dim: 64,
        num_heads: 4,
        num_quantiles: 5,
        prediction_horizon: 5,
        sequence_length: 20, // 20 timesteps history
        num_static_features: 2,
        num_known_features: 3,
        num_unknown_features: 5,
        ..Default::default()
    };

    let tft = TemporalFusionTransformer::new(config)?;
    assert_eq!(tft.metadata.input_dim, 10);
    assert_eq!(tft.metadata.output_dim, 5);
    assert!(!tft.is_trained);

    Ok(())
}

/// Test TFT state creation with real market data sequence length
#[tokio::test]
async fn test_tft_state_creation_real_data() -> Result<()> {
    // Skip if no real data available
    if !real_data_available().await {
        warn!("Skipping test: real data not available");
        return Ok(());
    }

    let config = TFTConfig {
        hidden_dim: 64,
        sequence_length: 20, // Real data sequence length
        num_heads: 4,
        ..Default::default()
    };

    let state = TFTState::zeros(&config)?;
    assert_eq!(state.last_update, 0);
    assert!(state.attention_cache.is_empty());

    Ok(())
}

/// Test TFT configuration validation with real data parameters
#[tokio::test]
async fn test_tft_config_validation_real_data() -> Result<()> {
    // Skip if no real data available
    if !real_data_available().await {
        warn!("Skipping test: real data not available");
        return Ok(());
    }

    // Load sequences to verify configuration matches data
    let sequences = load_tft_sequences(30, 50, 10).await?;
    if sequences.is_empty() {
        warn!("Skipping test: no sequences loaded");
        return Ok(());
    }

    let config = TFTConfig {
        input_dim: 10, // Match real data features
        hidden_dim: 64,
        num_heads: 4,
        num_layers: 2,
        prediction_horizon: 10,
        sequence_length: 50, // Match loaded sequence length
        num_quantiles: 7,
        num_static_features: 3,
        num_known_features: 5,
        num_unknown_features: 2, // 3 + 5 + 2 = 10 (fixed feature count mismatch)
        learning_rate: 0.001,
        batch_size: 32,
        dropout_rate: 0.1,
        l2_regularization: 0.0001,
        use_flash_attention: false,
        memory_efficient: true,
        max_inference_latency_us: 100,
        target_throughput_pps: 50_000,
    };

    // Validate all config parameters
    assert!(config.input_dim > 0);
    assert!(config.hidden_dim > 0);
    assert!(config.num_heads > 0);
    assert!(config.num_layers > 0);
    assert!(config.prediction_horizon > 0);
    assert!(config.sequence_length > 0);
    assert!(config.num_quantiles > 0);
    assert!(config.learning_rate > 0.0);
    assert!(config.batch_size > 0);
    assert!(config.dropout_rate >= 0.0 && config.dropout_rate < 1.0);
    assert!(config.max_inference_latency_us > 0);
    assert!(config.target_throughput_pps > 0);

    // Create model with validated config
    let tft = TemporalFusionTransformer::new(config)?;
    assert_eq!(tft.metadata.input_dim, 10);
    assert_eq!(tft.metadata.output_dim, 10);
    assert!(!tft.is_trained);

    Ok(())
}
