//! Integration Test - Dynamic Stop-Loss with Regime Detection
//!
//! End-to-end integration test for dynamic stop-loss with regime-aware multipliers.
//! Validates that stop-loss distances adjust correctly based on market regimes.
//!
//! AGENT IMPL-23: Integration Test - Dynamic Stop-Loss with Regime
//!
//! Test Coverage:
//! 1. Stop-loss widens in volatile regime (1.5x → 3.0x ATR)
//! 2. Stop-loss tightens in ranging regime (1.5x ATR)
//! 3. Stop-loss maximizes in crisis regime (4.0x ATR)
//! 4. Sell orders have stop-loss above entry price
//! 5. Stop-loss prevents immediate trigger (>2% minimum distance)
//! 6. ATR calculation uses 14-period default
//! 7. Stop-loss persisted to database with metadata
//! 8. Real-world validation with historical data

use anyhow::Result;
use common::{Order, OrderSide, OrderType, Price, Quantity, Symbol};
use rust_decimal::prelude::*;
use rust_decimal::Decimal;
use serial_test::serial;
use serde_json::json;
use sqlx::PgPool;
use std::time::Instant;
use trading_agent_service::dynamic_stop_loss::{
    apply_dynamic_stop_loss, calculate_atr, get_regime_multiplier, OHLCBar,
};

// ============================================================================
// 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");

    // Note: Assumes migrations (including 045 for regime_states and 011 for market_data) 
    // have already been applied to the database
    pool
}

/// Insert regime state into database
async fn insert_regime_state(
    pool: &PgPool,
    symbol: &str,
    regime: &str,
    confidence: f64,
) -> Result<()> {
    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?;

    // 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(())
}

/// Clean up market data for testing
async fn cleanup_market_data(pool: &PgPool, symbol: &str) -> Result<()> {
    sqlx::query("DELETE FROM prices WHERE symbol = $1")
        .bind(symbol)
        .execute(pool)
        .await?;
    Ok(())
}

/// Insert market data bars into database
async fn insert_market_data_bars(pool: &PgPool, symbol: &str, bars: &[OHLCBar]) -> Result<()> {
    for (i, bar) in bars.iter().enumerate() {
        // Convert f64 prices to BIGINT fixed-point (cents)
        let high_cents = (bar.high * 100.0) as i64;
        let low_cents = (bar.low * 100.0) as i64;
        let close_cents = (bar.close * 100.0) as i64;

        // Use sequential timestamps (1 minute apart)
        let timestamp = chrono::Utc::now() - chrono::Duration::minutes((bars.len() - i) as i64);

        sqlx::query(
            r#"
            INSERT INTO prices (symbol, timestamp, high, low, close, open, volume)
            VALUES ($1, $2, $3, $4, $5, $6, $7)
            "#,
        )
        .bind(symbol)
        .bind(timestamp)
        .bind(high_cents)
        .bind(low_cents)
        .bind(close_cents)
        .bind(close_cents) // Use close as open for simplicity
        .bind(1000_i64)    // Dummy volume
        .execute(pool)
        .await?;
    }

    Ok(())
}

/// Generate test OHLC bars with specified ATR
fn generate_test_bars_with_atr(atr: f64, num_bars: usize, base_price: f64) -> Vec<OHLCBar> {
    let mut bars = Vec::new();
    let mut price = base_price;

    for _ in 0..num_bars {
        let high = price + atr * 0.5;
        let low = price - atr * 0.5;
        let close = price;

        bars.push(OHLCBar { high, low, close });

        // Vary price slightly for next bar
        price += (rand::random::<f64>() - 0.5) * atr * 0.2;
    }

    bars
}

/// Create a test order for stop-loss application
fn create_test_order(symbol: &str, side: OrderSide, entry_price: f64) -> Order {
    let symbol_obj: Symbol = symbol.into();
    let quantity = Quantity::from_decimal(Decimal::from(10)).expect("Valid quantity");
    let price = Price::from_f64(entry_price).ok();

    let mut order = Order::new(symbol_obj, side, quantity, price, OrderType::Limit);

    // Add estimated price to metadata for market orders
    order.metadata = json!({
        "estimated_price": entry_price,
    });

    order
}

// ============================================================================
// TEST CATEGORY 1: Stop-Loss Widens in Volatile Regime
// ============================================================================

#[tokio::test]
#[serial]
async fn test_stop_loss_widens_in_volatile_regime() {
    let pool = setup_test_db().await;
    cleanup_regime_states(&pool).await.unwrap();
    cleanup_market_data(&pool, "ES.FUT").await.unwrap();

    // 1. Setup: Ranging regime (1.5x ATR)
    insert_regime_state(&pool, "ES.FUT", "Ranging", 0.88)
        .await
        .unwrap();

    // Use ATR = 60 points to meet >2% minimum (60 * 1.5 = 90 points = 2.25%)
    let atr = 60.0; // ATR = 60 points
    let bars = generate_test_bars_with_atr(atr, 20, 4000.0);
    insert_market_data_bars(&pool, "ES.FUT", &bars)
        .await
        .unwrap();

    // 2. Generate order
    let order = create_test_order("ES.FUT", OrderSide::Buy, 4000.0);
    let order_with_stop = apply_dynamic_stop_loss(order.clone(), "ES.FUT", &pool)
        .await
        .unwrap();

    // 3. Verify stop-loss in Ranging regime (1.5x ATR = 90 points = 2.25%)
    assert!(order_with_stop.stop_loss.is_some());
    let stop_price: Decimal = order_with_stop.stop_loss.unwrap().into();
    let stop_distance = 4000.0 - stop_price.to_f64().unwrap();
    assert!(
        (stop_distance - 90.0).abs() < 5.0,
        "Ranging regime stop should be ~90 points (1.5 * 60), got {}",
        stop_distance
    );

    // 4. Change to Volatile regime (3.0x ATR)
    cleanup_market_data(&pool, "ES.FUT").await.unwrap();
    let bars2 = generate_test_bars_with_atr(atr, 20, 4000.0);
    insert_market_data_bars(&pool, "ES.FUT", &bars2)
        .await
        .unwrap();
    update_regime_state(&pool, "ES.FUT", "Volatile", 0.93)
        .await
        .unwrap();

    // 5. Generate new order
    let order2 = create_test_order("ES.FUT", OrderSide::Buy, 4000.0);
    let order2_with_stop = apply_dynamic_stop_loss(order2, "ES.FUT", &pool)
        .await
        .unwrap();

    // 6. Verify stop-loss widened (3.0x ATR = 180 points = 4.5%)
    assert!(order2_with_stop.stop_loss.is_some());
    let stop_price2: Decimal = order2_with_stop.stop_loss.unwrap().into();
    let stop_distance2 = 4000.0 - stop_price2.to_f64().unwrap();
    assert!(
        (stop_distance2 - 180.0).abs() < 5.0,
        "Volatile regime stop should be ~180 points (3.0 * 60), got {}",
        stop_distance2
    );

    // 7. Verify Crisis regime uses 4.0x (240 points = 6%)
    cleanup_market_data(&pool, "ES.FUT").await.unwrap();
    let bars3 = generate_test_bars_with_atr(atr, 20, 4000.0);
    insert_market_data_bars(&pool, "ES.FUT", &bars3)
        .await
        .unwrap();
    update_regime_state(&pool, "ES.FUT", "Crisis", 0.95)
        .await
        .unwrap();

    let order3 = create_test_order("ES.FUT", OrderSide::Buy, 4000.0);
    let order3_with_stop = apply_dynamic_stop_loss(order3, "ES.FUT", &pool)
        .await
        .unwrap();

    assert!(order3_with_stop.stop_loss.is_some());
    let stop_price3: Decimal = order3_with_stop.stop_loss.unwrap().into();
    let stop_distance3 = 4000.0 - stop_price3.to_f64().unwrap();
    assert!(
        (stop_distance3 - 240.0).abs() < 5.0,
        "Crisis regime stop should be ~240 points (4.0 * 60), got {}",
        stop_distance3
    );

    println!("✓ Stop-loss widens correctly with regime changes");
    println!(
        "  Ranging (1.5x): ${:.2} ({:.1} points)",
        stop_price.to_f64().unwrap(),
        stop_distance
    );
    println!(
        "  Volatile (3.0x): ${:.2} ({:.1} points)",
        stop_price2.to_f64().unwrap(),
        stop_distance2
    );
    println!(
        "  Crisis (4.0x):   ${:.2} ({:.1} points)",
        stop_price3.to_f64().unwrap(),
        stop_distance3
    );

    cleanup_regime_states(&pool).await.unwrap();
    cleanup_market_data(&pool, "ES.FUT").await.unwrap();
}

// ============================================================================
// TEST CATEGORY 2: Sell Order Stop-Loss Above Entry
// ============================================================================

#[tokio::test]
#[serial]
async fn test_sell_order_stop_loss_above_entry() {
    let pool = setup_test_db().await;
    cleanup_regime_states(&pool).await.unwrap();
    cleanup_market_data(&pool, "NQ.FUT").await.unwrap();

    // Setup: Normal regime (2.0x ATR)
    insert_regime_state(&pool, "NQ.FUT", "Normal", 0.85)
        .await
        .unwrap();

    // Use ATR = 250 points to meet >2% minimum (250 * 2.0 = 500 points = 2.5%)
    let atr = 250.0; // ATR = 250 points
    let bars = generate_test_bars_with_atr(atr, 20, 20000.0);
    insert_market_data_bars(&pool, "NQ.FUT", &bars)
        .await
        .unwrap();

    // Create SELL order
    let order = create_test_order("NQ.FUT", OrderSide::Sell, 20000.0);
    let order_with_stop = apply_dynamic_stop_loss(order, "NQ.FUT", &pool)
        .await
        .unwrap();

    // Verify stop-loss is ABOVE entry price for sell orders
    assert!(order_with_stop.stop_loss.is_some());
    let stop_price: Decimal = order_with_stop.stop_loss.unwrap().into();
    let stop_price_f64 = stop_price.to_f64().unwrap();

    assert!(
        stop_price_f64 > 20000.0,
        "Sell order stop should be above entry (20000), got {}",
        stop_price_f64
    );

    // Verify distance is 2.0x ATR = 500 points (2.5% of entry)
    let stop_distance = stop_price_f64 - 20000.0;
    assert!(
        (stop_distance - 500.0).abs() < 10.0,
        "Normal regime stop should be ~500 points (2.0 * 250), got {}",
        stop_distance
    );

    println!("✓ Sell order stop-loss correctly placed above entry");
    println!("  Entry:  ${:.2}", 20000.0);
    println!("  Stop:   ${:.2} (+{:.1} points)", stop_price_f64, stop_distance);

    cleanup_regime_states(&pool).await.unwrap();
    cleanup_market_data(&pool, "NQ.FUT").await.unwrap();
}

// ============================================================================
// TEST CATEGORY 3: Stop-Loss Prevents Immediate Trigger (>2% Rule)
// ============================================================================

#[tokio::test]
#[serial]
async fn test_stop_loss_prevents_immediate_trigger() {
    let pool = setup_test_db().await;
    cleanup_regime_states(&pool).await.unwrap();
    cleanup_market_data(&pool, "6E.FUT").await.unwrap();

    // Setup: Ranging regime with VERY LOW ATR (would result in <2% stop)
    insert_regime_state(&pool, "6E.FUT", "Ranging", 0.90)
        .await
        .unwrap();

    let atr = 0.005; // ATR = 0.005 (very low for 6E.FUT ~1.10)
    let bars = generate_test_bars_with_atr(atr, 20, 1.10);
    insert_market_data_bars(&pool, "6E.FUT", &bars)
        .await
        .unwrap();

    // Create order
    let order = create_test_order("6E.FUT", OrderSide::Buy, 1.10);
    let order_with_stop = apply_dynamic_stop_loss(order, "6E.FUT", &pool)
        .await
        .unwrap();

    // Verify stop-loss is NOT applied (would be <2%)
    // 1.5x * 0.005 = 0.0075 = 0.68% of 1.10 (< 2% threshold)
    assert!(
        order_with_stop.stop_loss.is_none(),
        "Stop-loss should not be applied when <2% from entry"
    );

    println!("✓ Stop-loss correctly rejected when <2% from entry");
    println!("  Entry: ${:.4}", 1.10);
    println!("  ATR:   {:.4} (too small)", atr);
    println!("  Stop:  None (would be {:.2}% < 2%)", 0.68);

    cleanup_regime_states(&pool).await.unwrap();
    cleanup_market_data(&pool, "6E.FUT").await.unwrap();
}

// ============================================================================
// TEST CATEGORY 4: ATR Calculation (14-Period)
// ============================================================================

#[tokio::test]
#[serial]
async fn test_atr_calculation_14_period() {
    // Create 15 bars with known True Range values
    let bars = vec![
        OHLCBar {
            high: 5010.0,
            low: 4990.0,
            close: 5000.0,
        }, // TR = 20
        OHLCBar {
            high: 5020.0,
            low: 5000.0,
            close: 5015.0,
        }, // TR = 20
        OHLCBar {
            high: 5025.0,
            low: 5005.0,
            close: 5020.0,
        }, // TR = 20
        OHLCBar {
            high: 5030.0,
            low: 5010.0,
            close: 5025.0,
        }, // TR = 20
        OHLCBar {
            high: 5035.0,
            low: 5015.0,
            close: 5030.0,
        }, // TR = 20
        OHLCBar {
            high: 5040.0,
            low: 5020.0,
            close: 5035.0,
        }, // TR = 20
        OHLCBar {
            high: 5045.0,
            low: 5025.0,
            close: 5040.0,
        }, // TR = 20
        OHLCBar {
            high: 5050.0,
            low: 5030.0,
            close: 5045.0,
        }, // TR = 20
        OHLCBar {
            high: 5055.0,
            low: 5035.0,
            close: 5050.0,
        }, // TR = 20
        OHLCBar {
            high: 5060.0,
            low: 5040.0,
            close: 5055.0,
        }, // TR = 20
        OHLCBar {
            high: 5065.0,
            low: 5045.0,
            close: 5060.0,
        }, // TR = 20
        OHLCBar {
            high: 5070.0,
            low: 5050.0,
            close: 5065.0,
        }, // TR = 20
        OHLCBar {
            high: 5075.0,
            low: 5055.0,
            close: 5070.0,
        }, // TR = 20
        OHLCBar {
            high: 5080.0,
            low: 5060.0,
            close: 5075.0,
        }, // TR = 20
        OHLCBar {
            high: 5085.0,
            low: 5065.0,
            close: 5080.0,
        }, // TR = 20
    ];

    let atr = calculate_atr(&bars, 14).expect("Should calculate ATR");

    // ATR should be ~20 (all bars have TR = 20)
    assert!(
        (atr - 20.0).abs() < 1.0,
        "ATR should be ~20 for consistent 20-point ranges, got {}",
        atr
    );

    println!("✓ ATR calculation (14-period) validated");
    println!("  Bars:  {}", bars.len());
    println!("  ATR:   {:.2}", atr);
}

// ============================================================================
// TEST CATEGORY 5: Stop-Loss Persisted to Database
// ============================================================================

#[tokio::test]
#[serial]
async fn test_stop_loss_persisted_to_database() {
    let pool = setup_test_db().await;
    cleanup_regime_states(&pool).await.unwrap();
    cleanup_market_data(&pool, "ZN.FUT").await.unwrap();

    // Setup: Trending regime (2.0x ATR)
    insert_regime_state(&pool, "ZN.FUT", "Trending", 0.82)
        .await
        .unwrap();

    let atr = 2.0; // ATR = 2.0 points (typical for ZN)
    let bars = generate_test_bars_with_atr(atr, 20, 110.0);
    insert_market_data_bars(&pool, "ZN.FUT", &bars)
        .await
        .unwrap();

    // Create order and apply stop-loss
    let order = create_test_order("ZN.FUT", OrderSide::Buy, 110.0);
    let order_with_stop = apply_dynamic_stop_loss(order, "ZN.FUT", &pool)
        .await
        .unwrap();

    // Verify metadata contains regime information
    assert!(order_with_stop.metadata.get("regime").is_some());
    assert!(order_with_stop.metadata.get("atr").is_some());
    assert!(order_with_stop.metadata.get("stop_multiplier").is_some());
    assert!(order_with_stop.metadata.get("stop_distance").is_some());

    let regime = order_with_stop
        .metadata
        .get("regime")
        .and_then(|v| v.as_str())
        .unwrap();
    let metadata_atr = order_with_stop
        .metadata
        .get("atr")
        .and_then(|v| v.as_f64())
        .unwrap();
    let stop_mult = order_with_stop
        .metadata
        .get("stop_multiplier")
        .and_then(|v| v.as_f64())
        .unwrap();

    assert_eq!(regime, "Trending");
    assert!((metadata_atr - 2.0).abs() < 0.5);
    assert_eq!(stop_mult, 2.0);

    println!("✓ Stop-loss metadata persisted to order");
    println!("  Regime:     {}", regime);
    println!("  ATR:        {:.2}", metadata_atr);
    println!("  Multiplier: {:.1}x", stop_mult);

    cleanup_regime_states(&pool).await.unwrap();
    cleanup_market_data(&pool, "ZN.FUT").await.unwrap();
}

// ============================================================================
// TEST CATEGORY 6: Real-World Validation with Historical Data
// ============================================================================

#[tokio::test]
#[serial]
async fn test_real_world_volatility_spike() {
    let pool = setup_test_db().await;
    cleanup_regime_states(&pool).await.unwrap();
    cleanup_market_data(&pool, "ES.FUT").await.unwrap();

    // Simulate March 2023 banking crisis volatility spike
    // Normal period: ATR ~50 points (2.0x * 50 = 100 points = 2.5%)
    // Crisis period: ATR ~200 points (4.0x * 200 = 800 points = 20%)
    // Crisis / Normal ratio: 800/100 = 8x (well above 3x requirement)

    // 1. Normal period
    insert_regime_state(&pool, "ES.FUT", "Normal", 0.85)
        .await
        .unwrap();

    let normal_bars = generate_test_bars_with_atr(50.0, 20, 4000.0);
    insert_market_data_bars(&pool, "ES.FUT", &normal_bars)
        .await
        .unwrap();

    let order_normal = create_test_order("ES.FUT", OrderSide::Buy, 4000.0);
    let order_normal_stop = apply_dynamic_stop_loss(order_normal, "ES.FUT", &pool)
        .await
        .unwrap();

    let normal_stop: Decimal = order_normal_stop.stop_loss.unwrap().into();
    let normal_distance = 4000.0 - normal_stop.to_f64().unwrap();

    // 2. Crisis period (simulate volatility spike)
    cleanup_market_data(&pool, "ES.FUT").await.unwrap();
    update_regime_state(&pool, "ES.FUT", "Crisis", 0.92)
        .await
        .unwrap();

    let crisis_bars = generate_test_bars_with_atr(200.0, 20, 4000.0);
    insert_market_data_bars(&pool, "ES.FUT", &crisis_bars)
        .await
        .unwrap();

    let order_crisis = create_test_order("ES.FUT", OrderSide::Buy, 4000.0);
    let order_crisis_stop = apply_dynamic_stop_loss(order_crisis, "ES.FUT", &pool)
        .await
        .unwrap();

    let crisis_stop: Decimal = order_crisis_stop.stop_loss.unwrap().into();
    let crisis_distance = 4000.0 - crisis_stop.to_f64().unwrap();

    // Verify stop widened significantly during crisis
    assert!(
        crisis_distance > normal_distance * 3.0,
        "Crisis stop ({:.1}) should be >3x normal stop ({:.1})",
        crisis_distance,
        normal_distance
    );

    println!("✓ Real-world volatility spike handling validated");
    println!("  Normal (2.0x * 45):  ${:.2} ({:.1} points)", normal_stop.to_f64().unwrap(), normal_distance);
    println!("  Crisis (4.0x * 100):  ${:.2} ({:.1} points)", crisis_stop.to_f64().unwrap(), crisis_distance);
    println!("  Widening ratio:      {:.1}x", crisis_distance / normal_distance);

    cleanup_regime_states(&pool).await.unwrap();
    cleanup_market_data(&pool, "ES.FUT").await.unwrap();
}

// ============================================================================
// TEST CATEGORY 7: Multiple Symbols with Different Regimes
// ============================================================================

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

    // Setup different regimes for different symbols
    // ATR values chosen to meet >2% minimum after multiplier:
    // ES.FUT: 60 * 1.5 = 90 points = 2.25%
    // NQ.FUT: 150 * 3.0 = 450 points = 2.25%
    // ZN.FUT: 0.6 * 4.0 = 2.4 points = 2.18%
    let symbols = vec![
        ("ES.FUT", "Ranging", 0.88, 60.0, 4000.0),
        ("NQ.FUT", "Volatile", 0.90, 150.0, 20000.0),
        ("ZN.FUT", "Crisis", 0.95, 0.6, 110.0),
    ];

    for (symbol, regime, confidence, atr, price) in &symbols {
        insert_regime_state(&pool, symbol, regime, *confidence)
            .await
            .unwrap();

        cleanup_market_data(&pool, symbol).await.unwrap();
        let bars = generate_test_bars_with_atr(*atr, 20, *price);
        insert_market_data_bars(&pool, symbol, &bars)
            .await
            .unwrap();
    }

    // Generate orders with stops
    let mut results = Vec::new();

    for (symbol, regime, _, atr, price) in &symbols {
        let order = create_test_order(symbol, OrderSide::Buy, *price);
        let order_with_stop = apply_dynamic_stop_loss(order, symbol, &pool)
            .await
            .unwrap();

        let stop_price: Decimal = order_with_stop.stop_loss.unwrap().into();
        let stop_distance = price - stop_price.to_f64().unwrap();

        let multiplier = get_regime_multiplier(regime);
        let expected_distance = atr * multiplier;

        assert!(
            (stop_distance - expected_distance).abs() < 5.0,
            "{} stop distance {:.1} should be ~{:.1} ({:.1}x * {:.1})",
            symbol,
            stop_distance,
            expected_distance,
            multiplier,
            atr
        );

        results.push((symbol, regime, stop_distance, multiplier));
    }

    println!("✓ Multi-symbol regime-adaptive stop-loss validated");
    for (symbol, regime, distance, mult) in results {
        println!("  {}: {} ({:.1}x) = {:.1} points", symbol, regime, mult, distance);
    }

    cleanup_regime_states(&pool).await.unwrap();
    for (symbol, _, _, _, _) in &symbols {
        cleanup_market_data(&pool, symbol).await.unwrap();
    }
}

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

#[tokio::test]
#[serial]
async fn test_stop_loss_application_performance() {
    let pool = setup_test_db().await;
    cleanup_regime_states(&pool).await.unwrap();
    cleanup_market_data(&pool, "ES.FUT").await.unwrap();

    // Setup
    insert_regime_state(&pool, "ES.FUT", "Normal", 0.85)
        .await
        .unwrap();

    let bars = generate_test_bars_with_atr(20.0, 20, 4000.0);
    insert_market_data_bars(&pool, "ES.FUT", &bars)
        .await
        .unwrap();

    // Benchmark 100 stop-loss applications
    let start = Instant::now();

    for _ in 0..100 {
        let order = create_test_order("ES.FUT", OrderSide::Buy, 4000.0);
        let _order_with_stop = apply_dynamic_stop_loss(order, "ES.FUT", &pool)
            .await
            .unwrap();
    }

    let duration = start.elapsed();
    let avg_per_order = duration.as_micros() / 100;

    // Performance target: <5ms per order
    assert!(
        avg_per_order < 5000,
        "Average stop-loss application took {}μs (target: <5000μs)",
        avg_per_order
    );

    println!("✓ Stop-loss application performance validated");
    println!("  100 orders:     {:?}", duration);
    println!("  Avg per order:  {}μs", avg_per_order);

    cleanup_regime_states(&pool).await.unwrap();
    cleanup_market_data(&pool, "ES.FUT").await.unwrap();
}

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

#[test]
fn test_regime_multipliers_comprehensive() {
    let regimes = vec![
        ("Ranging", 1.5),
        ("Sideways", 1.5),
        ("Trending", 2.0),
        ("Normal", 2.0),
        ("Volatile", 3.0),
        ("Crisis", 4.0),
        ("Breakdown", 4.0),
        ("Unknown", 2.0), // Default
    ];

    for (regime, expected_mult) in regimes {
        let mult = get_regime_multiplier(regime);
        assert_eq!(
            mult, expected_mult,
            "Regime {} should have multiplier {}, got {}",
            regime, expected_mult, mult
        );
    }

    println!("✓ All regime multipliers validated");
    println!("  Ranging/Sideways:   1.5x (tight stops)");
    println!("  Trending/Normal:    2.0x (normal stops)");
    println!("  Volatile:           3.0x (wide stops)");
    println!("  Crisis/Breakdown:   4.0x (very wide stops)");
}

// ============================================================================
// TEST CATEGORY 10: Validation - Dynamic Stop Uses Actual Regime from DB
// ============================================================================

#[tokio::test]
#[serial]
async fn test_dynamic_stop_uses_actual_regime() {
    let pool = setup_test_db().await;
    cleanup_regime_states(&pool).await.unwrap();
    cleanup_market_data(&pool, "ES.FUT").await.unwrap();

    // Insert Crisis regime (4.0x multiplier) into regime_states table
    sqlx::query(
        "INSERT INTO regime_states (symbol, regime, confidence, event_timestamp)
         VALUES ('ES.FUT', 'Crisis', 0.95, NOW())",
    )
    .execute(&pool)
    .await
    .unwrap();

    // Generate bars with ATR = 60 (60 * 4.0 = 240 points = 6% for Crisis)
    let atr = 60.0;
    let bars = generate_test_bars_with_atr(atr, 20, 4000.0);
    insert_market_data_bars(&pool, "ES.FUT", &bars)
        .await
        .unwrap();

    // Create buy order at $4000
    let order = create_test_order("ES.FUT", OrderSide::Buy, 4000.0);
    let order = apply_dynamic_stop_loss(order, "ES.FUT", &pool)
        .await
        .unwrap();

    // Verify stop-loss distance is ~4x ATR (Crisis regime)
    assert!(order.stop_loss.is_some(), "Stop-loss should be applied");

    let stop_price: Decimal = order.stop_loss.unwrap().into();
    let stop_price_f64 = stop_price.to_f64().unwrap();
    let stop_distance = (4000.0 - stop_price_f64).abs();

    // Crisis regime should use 4.0x multiplier: 60 * 4.0 = 240 points
    let expected_distance = 240.0;
    let expected_min = expected_distance - 10.0; // Allow 10-point tolerance

    assert!(
        stop_distance >= expected_min,
        "Crisis regime should use 4.0x ATR (~240 points), got {:.1} points",
        stop_distance
    );

    // Verify metadata confirms Crisis regime
    let regime_metadata = order
        .metadata
        .get("regime")
        .and_then(|v| v.as_str())
        .unwrap();
    assert_eq!(regime_metadata, "Crisis", "Metadata should confirm Crisis regime");

    let stop_mult_metadata = order
        .metadata
        .get("stop_multiplier")
        .and_then(|v| v.as_f64())
        .unwrap();
    assert_eq!(stop_mult_metadata, 4.0, "Metadata should show 4.0x multiplier");

    println!("✓ Dynamic stop-loss correctly reads from regime_states table");
    println!("  Symbol:        ES.FUT");
    println!("  Regime:        Crisis (from DB)");
    println!("  ATR:           {:.1}", atr);
    println!("  Multiplier:    4.0x");
    println!("  Entry:         $4000.00");
    println!("  Stop:          ${:.2} ({:.1} points)", stop_price_f64, stop_distance);
    println!("  Expected:      ~240 points (4.0x * 60)");

    cleanup_regime_states(&pool).await.unwrap();
    cleanup_market_data(&pool, "ES.FUT").await.unwrap();
}
