//! Integration Test - Kelly Criterion + Regime Detection
//!
//! End-to-end integration test for Kelly allocation with regime multipliers.
//! Validates that regime-adaptive position sizing works correctly through
//! the full allocation pipeline.
//!
//! AGENT IMPL-20: Integration Test - Kelly Criterion + Regime Detection
//!
//! Test Coverage:
//! 1. Kelly allocation adapts to regime multipliers
//! 2. Regime change triggers reallocation
//! 3. Kelly falls back on missing regime data
//! 4. Crisis regime limits position sizes
//! 5. Allocation respects max 20% cap per asset
//! 6. Database persistence and retrieval
//! 7. Performance targets (<500ms allocation)

use anyhow::Result;
use rust_decimal::prelude::ToPrimitive;
use rust_decimal::Decimal;
use serial_test::serial;
use sqlx::PgPool;
use std::collections::HashMap;
use std::time::Instant;
use trading_agent_service::allocation::{AllocationMethod, AssetInfo, PortfolioAllocator};
use trading_agent_service::regime::{
    get_regime_for_symbol, get_regimes_for_symbols, regime_to_position_multiplier,
    regime_to_stoploss_multiplier,
};

// ============================================================================
// Test Setup Helpers
// ============================================================================

/// Setup test database with migrations
async fn setup_test_db() -> PgPool {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    // Run migrations (includes migration 045 for regime_states)
    sqlx::migrate!("../../migrations")
        .run(&pool)
        .await
        .expect("Failed to run migrations");

    pool
}

/// Insert regime state into database
async fn insert_regime_state(
    pool: &PgPool,
    symbol: &str,
    regime: &str,
    confidence: f64,
) -> Result<()> {
    // Add small delay to ensure unique timestamps
    tokio::time::sleep(tokio::time::Duration::from_millis(2)).await;

    sqlx::query(
        r#"
        INSERT INTO regime_states (symbol, event_timestamp, regime, confidence)
        VALUES ($1, NOW(), $2, $3)
        ON CONFLICT (symbol, event_timestamp)
        DO UPDATE SET regime = EXCLUDED.regime, confidence = EXCLUDED.confidence
        "#,
    )
    .bind(symbol)
    .bind(regime)
    .bind(confidence)
    .execute(pool)
    .await?;

    Ok(())
}

/// Update regime state in database
async fn update_regime_state(
    pool: &PgPool,
    symbol: &str,
    regime: &str,
    confidence: f64,
) -> Result<()> {
    // Delete old regime state
    sqlx::query("DELETE FROM regime_states WHERE symbol = $1")
        .bind(symbol)
        .execute(pool)
        .await?;

    // Add 1 millisecond delay to ensure different timestamp
    tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;

    // Insert new regime state
    insert_regime_state(pool, symbol, regime, confidence).await
}

/// Clean up regime states for testing
async fn cleanup_regime_states(pool: &PgPool) -> Result<()> {
    sqlx::query("DELETE FROM regime_states")
        .execute(pool)
        .await?;
    Ok(())
}

/// Create test asset info with Kelly parameters
fn create_test_asset(
    symbol: &str,
    expected_return: f64,
    volatility: f64,
    win_rate: f64,
    avg_win: f64,
    avg_loss: f64,
) -> AssetInfo {
    AssetInfo {
        symbol: symbol.to_string(),
        expected_return,
        volatility,
        ml_score: 0.65, // Placeholder
        win_rate,
        avg_win,
        avg_loss,
    }
}

// ============================================================================
// TEST CATEGORY 1: Kelly Allocation with Regime Multipliers
// ============================================================================

#[tokio::test]
#[serial]
async fn test_kelly_allocation_adapts_to_regime() {
    let pool = setup_test_db().await;
    cleanup_regime_states(&pool).await.unwrap();

    // Setup: Insert regime states
    // ES.FUT: Trending (1.5x position multiplier)
    // NQ.FUT: Crisis (0.2x position multiplier)
    insert_regime_state(&pool, "ES.FUT", "Trending", 0.85)
        .await
        .unwrap();
    insert_regime_state(&pool, "NQ.FUT", "Crisis", 0.92)
        .await
        .unwrap();

    // Create test assets with similar Kelly fractions
    let assets = vec![
        create_test_asset(
            "ES.FUT",
            0.10,  // 10% expected return
            0.15,  // 15% volatility
            0.55,  // 55% win rate
            150.0, // $150 avg win
            100.0, // $100 avg loss
        ),
        create_test_asset(
            "NQ.FUT",
            0.12,  // 12% expected return
            0.20,  // 20% volatility
            0.55,  // 55% win rate (same as ES)
            150.0, // $150 avg win (same as ES)
            100.0, // $100 avg loss (same as ES)
        ),
    ];

    // Allocate capital using Kelly Criterion (quarter Kelly = 0.25)
    let allocator = PortfolioAllocator::new(AllocationMethod::KellyCriterion { fraction: 0.25 });
    let total_capital = Decimal::from(100_000);

    let start = Instant::now();
    let base_allocation = allocator.allocate(&assets, total_capital).unwrap();
    let allocation_duration = start.elapsed();

    // Retrieve regime states
    let es_regime = get_regime_for_symbol(&pool, "ES.FUT").await.unwrap();
    let nq_regime = get_regime_for_symbol(&pool, "NQ.FUT").await.unwrap();

    // Apply regime multipliers to base allocation
    let mut regime_adjusted_allocation = HashMap::new();

    for (symbol, capital) in &base_allocation {
        let regime = if symbol == "ES.FUT" {
            &es_regime
        } else if symbol == "NQ.FUT" {
            &nq_regime
        } else {
            panic!("Unexpected symbol: {}", symbol);
        };

        let multiplier = regime_to_position_multiplier(&regime.regime);
        let adjusted_capital = *capital * Decimal::from_f64_retain(multiplier).unwrap();
        regime_adjusted_allocation.insert(symbol.clone(), adjusted_capital);
    }

    // Normalize to ensure total doesn't exceed 100%
    let total_adjusted: Decimal = regime_adjusted_allocation.values().sum();
    if total_adjusted > total_capital {
        for capital in regime_adjusted_allocation.values_mut() {
            *capital = (*capital / total_adjusted) * total_capital;
        }
    }

    // Verify ES (Trending, 1.5x) gets MORE capital than NQ (Crisis, 0.2x)
    let es_alloc = regime_adjusted_allocation.get("ES.FUT").expect("INVARIANT: Key should exist in map");
    let nq_alloc = regime_adjusted_allocation.get("NQ.FUT").expect("INVARIANT: Key should exist in map");

    assert!(
        *es_alloc > *nq_alloc * Decimal::from(5),
        "ES (Trending 1.5x) should get >5x capital of NQ (Crisis 0.2x). ES: {}, NQ: {}",
        es_alloc,
        nq_alloc
    );

    // Verify total capital allocated is LESS than total capital when regime multipliers reduce positions
    // (ES: 1.5x Trending, NQ: 0.2x Crisis means overall reduction)
    let total: Decimal = regime_adjusted_allocation.values().sum();
    assert!(
        total <= total_capital,
        "Total allocation {} should not exceed total capital {}",
        total,
        total_capital
    );

    // Verify total is significantly reduced due to Crisis regime (should be < 20% of capital)
    assert!(
        total < total_capital * Decimal::from_f64_retain(0.20).unwrap(),
        "Total allocation {} should be <20% of capital {} due to Crisis regime (0.2x multiplier)",
        total,
        total_capital
    );

    // Verify regime multipliers
    assert_eq!(
        regime_to_position_multiplier(&es_regime.regime),
        1.5,
        "Trending regime should have 1.5x multiplier"
    );
    assert_eq!(
        regime_to_position_multiplier(&nq_regime.regime),
        0.2,
        "Crisis regime should have 0.2x multiplier"
    );

    // Verify performance target (<500ms)
    assert!(
        allocation_duration.as_millis() < 500,
        "Allocation took {}ms (target: <500ms)",
        allocation_duration.as_millis()
    );

    println!(
        "✓ Kelly allocation with regime multipliers completed in {}ms",
        allocation_duration.as_millis()
    );
    println!("  ES.FUT (Trending 1.5x): ${}", es_alloc);
    println!("  NQ.FUT (Crisis 0.2x):   ${}", nq_alloc);

    cleanup_regime_states(&pool).await.unwrap();
}

// ============================================================================
// TEST CATEGORY 2: Regime Change Triggers Reallocation
// ============================================================================

#[tokio::test]
#[serial]
async fn test_regime_change_triggers_reallocation() {
    let pool = setup_test_db().await;
    cleanup_regime_states(&pool).await.unwrap();

    // Initial state: ES.FUT in Normal regime (1.0x)
    insert_regime_state(&pool, "ES.FUT", "Normal", 0.80)
        .await
        .unwrap();

    let asset = create_test_asset("ES.FUT", 0.10, 0.15, 0.55, 150.0, 100.0);
    let allocator = PortfolioAllocator::new(AllocationMethod::KellyCriterion { fraction: 0.25 });
    let total_capital = Decimal::from(100_000);

    // Initial allocation
    let initial_allocation = allocator.allocate(std::slice::from_ref(&asset), total_capital).unwrap();
    let initial_capital = initial_allocation.get("ES.FUT").expect("INVARIANT: Key should exist in map");

    let initial_regime = get_regime_for_symbol(&pool, "ES.FUT").await.unwrap();
    let initial_multiplier = regime_to_position_multiplier(&initial_regime.regime);

    // Change regime to Trending (1.5x)
    update_regime_state(&pool, "ES.FUT", "Trending", 0.85)
        .await
        .unwrap();

    // Reallocation after regime change
    let new_allocation = allocator.allocate(&[asset], total_capital).unwrap();
    let new_capital_base = new_allocation.get("ES.FUT").expect("INVARIANT: Key should exist in map");

    let new_regime = get_regime_for_symbol(&pool, "ES.FUT").await.unwrap();
    let new_multiplier = regime_to_position_multiplier(&new_regime.regime);

    // Apply regime multipliers
    let initial_adjusted =
        *initial_capital * Decimal::from_f64_retain(initial_multiplier).unwrap();
    let new_adjusted = *new_capital_base * Decimal::from_f64_retain(new_multiplier).unwrap();

    // Verify allocation increased due to regime change (Normal 1.0x → Trending 1.5x)
    assert!(
        new_adjusted > initial_adjusted,
        "Allocation should increase when regime changes from Normal (1.0x) to Trending (1.5x)"
    );

    // Verify multiplier change
    assert_eq!(initial_multiplier, 1.0);
    assert_eq!(new_multiplier, 1.5);

    println!("✓ Regime change from Normal to Trending triggered reallocation");
    println!(
        "  Initial (Normal 1.0x):   ${}",
        initial_adjusted.round_dp(2)
    );
    println!("  New (Trending 1.5x):    ${}", new_adjusted.round_dp(2));
    println!(
        "  Increase:               {:.1}%",
        ((new_adjusted - initial_adjusted) / initial_adjusted * Decimal::from(100))
            .to_f64()
            .unwrap()
    );

    cleanup_regime_states(&pool).await.unwrap();
}

// ============================================================================
// TEST CATEGORY 3: Fallback on Missing Regime
// ============================================================================

#[tokio::test]
#[serial]
async fn test_kelly_falls_back_on_missing_regime() {
    let pool = setup_test_db().await;
    cleanup_regime_states(&pool).await.unwrap();

    // Do NOT insert regime state for ZN.FUT (missing regime)
    let asset = create_test_asset("ZN.FUT", 0.08, 0.12, 0.53, 100.0, 90.0);
    let allocator = PortfolioAllocator::new(AllocationMethod::KellyCriterion { fraction: 0.25 });
    let total_capital = Decimal::from(100_000);

    // Allocation should still work (fallback to Normal regime)
    let allocation = allocator.allocate(&[asset], total_capital).unwrap();
    let allocated_capital = allocation.get("ZN.FUT").expect("INVARIANT: Key should exist in map");

    // Attempt to get regime (should fail)
    let regime_result = get_regime_for_symbol(&pool, "ZN.FUT").await;
    assert!(
        regime_result.is_err(),
        "Should not have regime data for ZN.FUT"
    );

    // Fallback to Normal regime (1.0x multiplier)
    let fallback_multiplier = regime_to_position_multiplier("Normal");
    assert_eq!(fallback_multiplier, 1.0);

    // Verify allocation succeeded with fallback
    assert!(
        *allocated_capital > Decimal::ZERO,
        "Should allocate capital even without regime data"
    );
    assert!(
        *allocated_capital <= total_capital,
        "Should not exceed total capital"
    );

    println!("✓ Kelly allocation succeeded with missing regime (fallback to Normal 1.0x)");
    println!("  ZN.FUT (fallback):      ${}", allocated_capital);

    cleanup_regime_states(&pool).await.unwrap();
}

// ============================================================================
// TEST CATEGORY 4: Crisis Regime Limits Position Sizes
// ============================================================================

#[tokio::test]
#[serial]
async fn test_crisis_regime_limits_position_sizes() {
    let pool = setup_test_db().await;
    cleanup_regime_states(&pool).await.unwrap();

    // Setup: 3 assets, all in Crisis regime (0.2x)
    let symbols = vec!["ES.FUT", "NQ.FUT", "6E.FUT"];
    for symbol in &symbols {
        insert_regime_state(&pool, symbol, "Crisis", 0.90)
            .await
            .unwrap();
    }

    let assets = vec![
        create_test_asset("ES.FUT", 0.10, 0.15, 0.55, 150.0, 100.0),
        create_test_asset("NQ.FUT", 0.12, 0.20, 0.52, 200.0, 120.0),
        create_test_asset("6E.FUT", 0.08, 0.12, 0.53, 80.0, 70.0),
    ];

    let allocator = PortfolioAllocator::new(AllocationMethod::KellyCriterion { fraction: 0.25 });
    let total_capital = Decimal::from(100_000);

    // Base allocation
    let base_allocation = allocator.allocate(&assets, total_capital).unwrap();

    // Apply Crisis regime multiplier (0.2x)
    let crisis_multiplier = regime_to_position_multiplier("Crisis");
    assert_eq!(crisis_multiplier, 0.2);

    let mut total_crisis_capital = Decimal::ZERO;
    for (symbol, capital) in &base_allocation {
        let adjusted = *capital * Decimal::from_f64_retain(crisis_multiplier).unwrap();
        total_crisis_capital += adjusted;
        println!("  {} (Crisis 0.2x): ${}", symbol, adjusted);
    }

    // Verify total allocation is severely reduced (should be ~20% of normal)
    let max_expected = total_capital * Decimal::from_f64_retain(0.3).unwrap(); // 30% max
    assert!(
        total_crisis_capital < max_expected,
        "Crisis regime should severely limit total allocation. Total: {}, Max: {}",
        total_crisis_capital,
        max_expected
    );

    println!("✓ Crisis regime limits position sizes to 20%");
    println!(
        "  Total crisis allocation: ${} ({:.1}% of capital)",
        total_crisis_capital,
        (total_crisis_capital / total_capital * Decimal::from(100))
            .to_f64()
            .unwrap()
    );

    cleanup_regime_states(&pool).await.unwrap();
}

// ============================================================================
// TEST CATEGORY 5: Allocation Respects Max 20% Cap
// ============================================================================

#[tokio::test]
#[serial]
async fn test_allocation_respects_max_20_percent_cap() {
    let pool = setup_test_db().await;
    cleanup_regime_states(&pool).await.unwrap();

    // Setup: Single asset with very high win rate (would exceed 20% without cap)
    insert_regime_state(&pool, "ES.FUT", "Trending", 0.90)
        .await
        .unwrap();

    let asset = create_test_asset(
        "ES.FUT",
        0.25,  // 25% expected return (very high)
        0.15,  // 15% volatility
        0.75,  // 75% win rate (very high)
        500.0, // $500 avg win
        100.0, // $100 avg loss
    );

    let allocator = PortfolioAllocator::new(AllocationMethod::KellyCriterion { fraction: 1.0 });
    // Use full Kelly (fraction=1.0) to test cap
    let total_capital = Decimal::from(100_000);

    let allocation = allocator.allocate(&[asset], total_capital).unwrap();
    let allocated_capital = allocation.get("ES.FUT").expect("INVARIANT: Key should exist in map");

    // Calculate weight
    let weight = *allocated_capital / total_capital;

    // Verify weight does NOT exceed 20% (even with very favorable Kelly parameters)
    assert!(
        weight <= Decimal::from_f64_retain(0.20).unwrap(),
        "Weight {} exceeds max 20% cap",
        weight
    );

    println!("✓ Kelly allocation respects max 20% position size cap");
    println!("  ES.FUT weight: {:.1}%", (weight * Decimal::from(100)).to_f64().unwrap());
    println!("  Allocated:     ${}", allocated_capital);

    cleanup_regime_states(&pool).await.unwrap();
}

// ============================================================================
// TEST CATEGORY 6: Multi-Symbol Regime Retrieval
// ============================================================================

#[tokio::test]
#[serial]
async fn test_multi_symbol_regime_retrieval() {
    let pool = setup_test_db().await;
    cleanup_regime_states(&pool).await.unwrap();

    // Setup: Multiple assets with different regimes
    insert_regime_state(&pool, "ES.FUT", "Trending", 0.85)
        .await
        .unwrap();
    insert_regime_state(&pool, "NQ.FUT", "Volatile", 0.78)
        .await
        .unwrap();
    insert_regime_state(&pool, "ZN.FUT", "Normal", 0.90)
        .await
        .unwrap();

    // Batch retrieve regimes
    let symbols = vec!["ES.FUT", "NQ.FUT", "ZN.FUT"];
    let start = Instant::now();
    let regimes = get_regimes_for_symbols(&pool, &symbols).await.unwrap();
    let retrieval_duration = start.elapsed();

    // Verify all regimes retrieved
    assert_eq!(regimes.len(), 3);

    let es_regime = regimes.iter().find(|r| r.symbol == "ES.FUT").unwrap();
    let nq_regime = regimes.iter().find(|r| r.symbol == "NQ.FUT").unwrap();
    let zn_regime = regimes.iter().find(|r| r.symbol == "ZN.FUT").unwrap();

    assert_eq!(es_regime.regime, "Trending");
    assert_eq!(nq_regime.regime, "Volatile");
    assert_eq!(zn_regime.regime, "Normal");

    // Verify confidence values
    assert_eq!(es_regime.confidence, 0.85);
    assert_eq!(nq_regime.confidence, 0.78);
    assert_eq!(zn_regime.confidence, 0.90);

    // Verify multipliers
    assert_eq!(regime_to_position_multiplier(&es_regime.regime), 1.5);
    assert_eq!(regime_to_position_multiplier(&nq_regime.regime), 0.5);
    assert_eq!(regime_to_position_multiplier(&zn_regime.regime), 1.0);

    // Performance target: Batch retrieval <100ms
    assert!(
        retrieval_duration.as_millis() < 100,
        "Batch regime retrieval took {}ms (target: <100ms)",
        retrieval_duration.as_millis()
    );

    println!(
        "✓ Multi-symbol regime retrieval completed in {}ms",
        retrieval_duration.as_millis()
    );
    println!("  ES.FUT: {} (conf: {:.2})", es_regime.regime, es_regime.confidence);
    println!("  NQ.FUT: {} (conf: {:.2})", nq_regime.regime, nq_regime.confidence);
    println!("  ZN.FUT: {} (conf: {:.2})", zn_regime.regime, zn_regime.confidence);

    cleanup_regime_states(&pool).await.unwrap();
}

// ============================================================================
// TEST CATEGORY 7: Stop-Loss Multipliers
// ============================================================================

#[tokio::test]
#[serial]
async fn test_regime_stoploss_multipliers() {
    let pool = setup_test_db().await;
    cleanup_regime_states(&pool).await.unwrap();

    // Setup: Different regimes for stop-loss validation
    insert_regime_state(&pool, "ES.FUT", "Ranging", 0.85)
        .await
        .unwrap();
    insert_regime_state(&pool, "NQ.FUT", "Crisis", 0.90)
        .await
        .unwrap();

    let es_regime = get_regime_for_symbol(&pool, "ES.FUT").await.unwrap();
    let nq_regime = get_regime_for_symbol(&pool, "NQ.FUT").await.unwrap();

    let es_stop_mult = regime_to_stoploss_multiplier(&es_regime.regime);
    let nq_stop_mult = regime_to_stoploss_multiplier(&nq_regime.regime);

    // Verify stop-loss multipliers
    assert_eq!(
        es_stop_mult, 1.5,
        "Ranging regime should have 1.5x stop-loss (tight stops)"
    );
    assert_eq!(
        nq_stop_mult, 4.0,
        "Crisis regime should have 4.0x stop-loss (wide stops)"
    );

    // Crisis should have wider stops than Ranging
    assert!(
        nq_stop_mult > es_stop_mult,
        "Crisis stops ({}) should be wider than Ranging stops ({})",
        nq_stop_mult,
        es_stop_mult
    );

    println!("✓ Regime-specific stop-loss multipliers validated");
    println!("  ES.FUT (Ranging): {:.1}x ATR", es_stop_mult);
    println!("  NQ.FUT (Crisis):  {:.1}x ATR", nq_stop_mult);

    cleanup_regime_states(&pool).await.unwrap();
}

// ============================================================================
// TEST CATEGORY 8: Performance Benchmarks
// ============================================================================

#[tokio::test]
#[serial]
async fn test_allocation_performance_50_assets() {
    let pool = setup_test_db().await;
    cleanup_regime_states(&pool).await.unwrap();

    // Setup: 50 assets with various regimes
    let mut assets = Vec::new();
    for i in 0..50 {
        let symbol = format!("ASSET_{}", i);
        let regime = match i % 5 {
            0 => "Trending",
            1 => "Normal",
            2 => "Volatile",
            3 => "Ranging",
            _ => "Crisis",
        };
        insert_regime_state(&pool, &symbol, regime, 0.80 + (i as f64 * 0.002))
            .await
            .unwrap();

        assets.push(create_test_asset(
            &symbol,
            0.08 + (i as f64 * 0.001),
            0.12 + (i as f64 * 0.002),
            0.50 + (i as f64 * 0.005),
            100.0 + (i as f64 * 2.0),
            80.0 + (i as f64 * 1.5),
        ));
    }

    let allocator = PortfolioAllocator::new(AllocationMethod::KellyCriterion { fraction: 0.25 });
    let total_capital = Decimal::from(1_000_000); // $1M portfolio

    // Benchmark allocation
    let start = Instant::now();
    let allocation = allocator.allocate(&assets, total_capital).unwrap();
    let allocation_duration = start.elapsed();

    // Verify allocation succeeded
    assert_eq!(allocation.len(), 50);

    // Performance target: <500ms for 50 assets
    assert!(
        allocation_duration.as_millis() < 500,
        "50-asset allocation took {}ms (target: <500ms)",
        allocation_duration.as_millis()
    );

    // Verify total allocation
    let total: Decimal = allocation.values().sum();
    assert!(
        total <= total_capital,
        "Total allocation {} exceeds capital {}",
        total,
        total_capital
    );

    println!(
        "✓ 50-asset Kelly allocation completed in {}ms",
        allocation_duration.as_millis()
    );
    println!(
        "  Total allocated: ${} ({:.1}%)",
        total,
        (total / total_capital * Decimal::from(100))
            .to_f64()
            .unwrap()
    );

    cleanup_regime_states(&pool).await.unwrap();
}

// ============================================================================
// TEST CATEGORY 9: Regime State Validation
// ============================================================================

#[tokio::test]
#[serial]
async fn test_regime_state_persistence() {
    let pool = setup_test_db().await;
    cleanup_regime_states(&pool).await.unwrap();

    // Insert regime with full metadata
    sqlx::query(
        r#"
        INSERT INTO regime_states (
            symbol, event_timestamp, regime, confidence,
            cusum_s_plus, cusum_s_minus, cusum_alert_count,
            adx, plus_di, minus_di,
            stability, entropy
        )
        VALUES ($1, NOW(), $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
        "#,
    )
    .bind("ES.FUT")
    .bind("Trending")
    .bind(0.85)
    .bind(2.5)  // cusum_s_plus
    .bind(-0.5) // cusum_s_minus
    .bind(3_i32)    // cusum_alert_count
    .bind(35.0) // adx
    .bind(28.0) // plus_di
    .bind(15.0) // minus_di
    .bind(0.92) // stability
    .bind(0.15)  // entropy
    .execute(&pool)
    .await
    .unwrap();

    // Retrieve and validate
    let regime = get_regime_for_symbol(&pool, "ES.FUT").await.unwrap();

    assert_eq!(regime.symbol, "ES.FUT");
    assert_eq!(regime.regime, "Trending");
    assert_eq!(regime.confidence, 0.85);
    assert_eq!(regime.adx, Some(35.0));
    assert_eq!(regime.plus_di, Some(28.0));
    assert_eq!(regime.minus_di, Some(15.0));

    println!("✓ Regime state persistence validated");
    println!("  Symbol:     {}", regime.symbol);
    println!("  Regime:     {}", regime.regime);
    println!("  Confidence: {:.2}", regime.confidence);
    println!("  ADX:        {:.1}", regime.adx.unwrap());

    cleanup_regime_states(&pool).await.unwrap();
}
