#![allow(unexpected_cfgs)]
#![cfg(feature = "__trading_service_integration")]
//! Wave D Paper Trading Integration Test
//!
//! This test validates the integration of Wave D regime detection features into
//! paper trading, enabling regime-adaptive position sizing and stop-loss adjustments.
//!
//! ## Test Coverage
//! 1. Regime-adaptive position sizing (1.0x Normal → 1.5x Trending → 0.5x Volatile → 0.2x Crisis)
//! 2. Dynamic stop-loss adjustment (2.0x ATR → 2.5x ATR → 3.0x ATR → 4.0x ATR)
//! 3. Regime transition logging to database
//! 4. Order submission with regime metadata
//! 5. Regime feature extraction from market data
//!
//! ## Architecture
//! - Uses real PostgreSQL for integration testing
//! - Simulates market data stream with regime transitions
//! - Validates position sizing calculations
//! - Tests database regime tracking
//!
//! ## TDD RED Phase
//! This test is expected to FAIL until paper trading executor is updated
//! with regime awareness (Agent D33 GREEN phase).

use anyhow::Result;
use chrono::Utc;
use sqlx::PgPool;
use std::collections::HashMap;
use uuid::Uuid;

// Import paper trading executor types
use trading_service::paper_trading_executor::{
    PaperTradingConfig, PaperTradingExecutor, PendingPrediction,
};

// Import Wave D regime types (will be created in GREEN phase)
// use common::trading::MarketRegime;

// Test database URL
fn get_test_db_url() -> String {
    std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    })
}

/// Helper to create test market data with regime characteristics
fn create_regime_market_data(regime: &str) -> Vec<(f64, f64, f64, f64, f64)> {
    // (timestamp, open, high, low, close, volume)
    match regime {
        "normal" => {
            // Normal market: Low volatility, small range
            vec![
                (1000.0, 4500.0, 4502.0, 4498.0, 4501.0, 100.0),
                (2000.0, 4501.0, 4503.0, 4499.0, 4500.0, 110.0),
                (3000.0, 4500.0, 4502.0, 4498.0, 4501.0, 105.0),
            ]
        },
        "trending" => {
            // Trending market: Strong directional movement
            vec![
                (1000.0, 4500.0, 4520.0, 4498.0, 4518.0, 150.0),
                (2000.0, 4518.0, 4540.0, 4515.0, 4538.0, 160.0),
                (3000.0, 4538.0, 4560.0, 4535.0, 4558.0, 155.0),
            ]
        },
        "volatile" => {
            // Volatile market: Large price swings
            vec![
                (1000.0, 4500.0, 4550.0, 4450.0, 4480.0, 200.0),
                (2000.0, 4480.0, 4530.0, 4420.0, 4520.0, 220.0),
                (3000.0, 4520.0, 4570.0, 4460.0, 4490.0, 210.0),
            ]
        },
        "crisis" => {
            // Crisis market: Extreme volatility, gap moves
            vec![
                (1000.0, 4500.0, 4600.0, 4350.0, 4380.0, 300.0),
                (2000.0, 4380.0, 4480.0, 4250.0, 4300.0, 350.0),
                (3000.0, 4300.0, 4400.0, 4150.0, 4200.0, 320.0),
            ]
        },
        _ => vec![],
    }
}

/// Calculate ATR (Average True Range) for stop-loss calculation
fn calculate_atr(market_data: &[(f64, f64, f64, f64, f64)]) -> f64 {
    if market_data.is_empty() {
        return 20.0; // Default ATR
    }

    let mut true_ranges = Vec::new();
    for window in market_data.windows(2) {
        let (_, _, _, _, prev_close) = window[0];
        let (_, _, high, low, _) = window[1];
        let tr = (high - low)
            .max((high - prev_close).abs())
            .max((low - prev_close).abs());
        true_ranges.push(tr);
    }

    if true_ranges.is_empty() {
        return 20.0;
    }

    true_ranges.iter().sum::<f64>() / true_ranges.len() as f64
}

// ============================================================================
// TEST 1: Regime-Adaptive Position Sizing
// ============================================================================

#[tokio::test]
async fn test_regime_adaptive_position_sizing() {
    let pool = PgPool::connect(&get_test_db_url())
        .await
        .expect("Failed to connect to test database");

    // Setup: Create paper trading executor with regime awareness
    let config = PaperTradingConfig::default();
    let executor = PaperTradingExecutor::new(pool.clone(), config);

    // Test Case 1: Normal regime → 1.0x base position size
    let normal_data = create_regime_market_data("normal");
    let base_position_size = 10.0; // 10 contracts base

    // Calculate expected position size for Normal regime
    let normal_multiplier = 1.0;
    let expected_normal_size = base_position_size * normal_multiplier;

    // Simulate regime detection (will be implemented in GREEN phase)
    let detected_regime = "Normal";

    println!(
        "TEST 1.1: Normal regime detected → Expected position size: {:.2} (base {} x multiplier {})",
        expected_normal_size, base_position_size, normal_multiplier
    );

    // Test Case 2: Trending regime → 1.5x base position size
    let trending_data = create_regime_market_data("trending");
    let trending_multiplier = 1.5;
    let expected_trending_size = base_position_size * trending_multiplier;

    println!(
        "TEST 1.2: Trending regime detected → Expected position size: {:.2} (base {} x multiplier {})",
        expected_trending_size, base_position_size, trending_multiplier
    );

    // Test Case 3: Volatile regime → 0.5x base position size
    let volatile_data = create_regime_market_data("volatile");
    let volatile_multiplier = 0.5;
    let expected_volatile_size = base_position_size * volatile_multiplier;

    println!(
        "TEST 1.3: Volatile regime detected → Expected position size: {:.2} (base {} x multiplier {})",
        expected_volatile_size, base_position_size, volatile_multiplier
    );

    // Test Case 4: Crisis regime → 0.2x base position size
    let crisis_data = create_regime_market_data("crisis");
    let crisis_multiplier = 0.2;
    let expected_crisis_size = base_position_size * crisis_multiplier;

    println!(
        "TEST 1.4: Crisis regime detected → Expected position size: {:.2} (base {} x multiplier {})",
        expected_crisis_size, base_position_size, crisis_multiplier
    );

    // RED PHASE: Expected to fail - executor does not yet implement regime-aware position sizing
    // GREEN PHASE: Will implement calculate_regime_adjusted_position_size() method

    println!("✗ RED: test_regime_adaptive_position_sizing - Not yet implemented");
}

// ============================================================================
// TEST 2: Dynamic Stop-Loss Adjustment
// ============================================================================

#[tokio::test]
async fn test_dynamic_stop_loss_adjustment() {
    let pool = PgPool::connect(&get_test_db_url())
        .await
        .expect("Failed to connect to test database");

    let config = PaperTradingConfig::default();
    let executor = PaperTradingExecutor::new(pool.clone(), config);

    // Test Case 1: Normal regime → 2.0x ATR stop-loss
    let normal_data = create_regime_market_data("normal");
    let atr = calculate_atr(&normal_data);
    let normal_multiplier = 2.0;
    let expected_normal_stop = atr * normal_multiplier;

    println!(
        "TEST 2.1: Normal regime → Stop-loss: {:.2} (ATR {:.2} x multiplier {})",
        expected_normal_stop, atr, normal_multiplier
    );

    // Test Case 2: Trending regime → 2.5x ATR stop-loss
    let trending_data = create_regime_market_data("trending");
    let atr = calculate_atr(&trending_data);
    let trending_multiplier = 2.5;
    let expected_trending_stop = atr * trending_multiplier;

    println!(
        "TEST 2.2: Trending regime → Stop-loss: {:.2} (ATR {:.2} x multiplier {})",
        expected_trending_stop, atr, trending_multiplier
    );

    // Test Case 3: Volatile regime → 3.0x ATR stop-loss
    let volatile_data = create_regime_market_data("volatile");
    let atr = calculate_atr(&volatile_data);
    let volatile_multiplier = 3.0;
    let expected_volatile_stop = atr * volatile_multiplier;

    println!(
        "TEST 2.3: Volatile regime → Stop-loss: {:.2} (ATR {:.2} x multiplier {})",
        expected_volatile_stop, atr, volatile_multiplier
    );

    // Test Case 4: Crisis regime → 4.0x ATR stop-loss
    let crisis_data = create_regime_market_data("crisis");
    let atr = calculate_atr(&crisis_data);
    let crisis_multiplier = 4.0;
    let expected_crisis_stop = atr * crisis_multiplier;

    println!(
        "TEST 2.4: Crisis regime → Stop-loss: {:.2} (ATR {:.2} x multiplier {})",
        expected_crisis_stop, atr, crisis_multiplier
    );

    // RED PHASE: Expected to fail - executor does not yet implement dynamic stop-loss
    // GREEN PHASE: Will implement calculate_regime_adjusted_stop_loss() method

    println!("✗ RED: test_dynamic_stop_loss_adjustment - Not yet implemented");
}

// ============================================================================
// TEST 3: Regime Transition Logging
// ============================================================================

#[tokio::test]
async fn test_regime_transition_logging() {
    let pool = PgPool::connect(&get_test_db_url())
        .await
        .expect("Failed to connect to test database");

    let config = PaperTradingConfig::default();
    let executor = PaperTradingExecutor::new(pool.clone(), config);

    // Setup: Create test prediction
    let prediction_id = Uuid::new_v4();
    sqlx::query!(
        r#"
        INSERT INTO ensemble_predictions (
            id, symbol, ensemble_action, ensemble_signal, ensemble_confidence, disagreement_rate
        ) VALUES (
            $1, 'ES.FUT', 'BUY', 0.75, 0.85, 0.10
        )
        "#,
        prediction_id,
    )
    .execute(&pool)
    .await
    .expect("Failed to insert test prediction");

    // Simulate regime transitions: Normal → Trending → Volatile → Crisis
    let regime_sequence = vec!["Normal", "Trending", "Volatile", "Crisis"];

    println!("TEST 3: Simulating regime transitions:");
    for (i, regime) in regime_sequence.iter().enumerate() {
        println!("  Step {}: Transition to {} regime", i + 1, regime);

        // RED PHASE: Expected to fail - no regime logging implemented
        // GREEN PHASE: Will implement log_regime_transition() method
        // Expected: Insert into regime_transitions table with:
        // - prediction_id
        // - previous_regime
        // - new_regime
        // - transition_timestamp
        // - confidence_score
    }

    // Verify regime transitions were logged
    // RED PHASE: This query will fail because regime_transitions table doesn't exist yet
    // GREEN PHASE: Will create migration and verify insertions

    println!("✗ RED: test_regime_transition_logging - Not yet implemented");
}

// ============================================================================
// TEST 4: Order Submission with Regime Metadata
// ============================================================================

#[tokio::test]
async fn test_order_submission_with_regime_metadata() {
    let pool = PgPool::connect(&get_test_db_url())
        .await
        .expect("Failed to connect to test database");

    let config = PaperTradingConfig::default();
    let executor = PaperTradingExecutor::new(pool.clone(), config);

    // Setup: Create test prediction with regime metadata
    let prediction_id = Uuid::new_v4();
    sqlx::query!(
        r#"
        INSERT INTO ensemble_predictions (
            id, symbol, ensemble_action, ensemble_signal, ensemble_confidence, disagreement_rate
        ) VALUES (
            $1, 'ES.FUT', 'BUY', 0.75, 0.85, 0.10
        )
        "#,
        prediction_id,
    )
    .execute(&pool)
    .await
    .expect("Failed to insert test prediction");

    // Simulate order submission with regime metadata
    let trending_data = create_regime_market_data("trending");
    let base_size = 10.0;
    let regime_multiplier = 1.5;
    let adjusted_size = base_size * regime_multiplier;

    println!(
        "TEST 4: Submitting order with regime metadata: Trending regime, adjusted size: {:.2}",
        adjusted_size
    );

    // RED PHASE: Expected to fail - orders table doesn't have regime columns yet
    // GREEN PHASE: Will add columns to orders table:
    // - regime_detected VARCHAR(50)
    // - regime_confidence DOUBLE PRECISION
    // - position_multiplier DOUBLE PRECISION
    // - stop_loss_multiplier DOUBLE PRECISION

    println!("✗ RED: test_order_submission_with_regime_metadata - Not yet implemented");
}

// ============================================================================
// TEST 5: End-to-End Regime-Adaptive Paper Trading
// ============================================================================

#[tokio::test]
async fn test_e2e_regime_adaptive_paper_trading() {
    let pool = PgPool::connect(&get_test_db_url())
        .await
        .expect("Failed to connect to test database");

    let config = PaperTradingConfig::default();
    let executor = PaperTradingExecutor::new(pool.clone(), config);

    println!("TEST 5: End-to-End Regime-Adaptive Paper Trading");

    // Step 1: Start with Normal regime
    println!("  Step 1: Normal regime - Base position sizing");
    let normal_data = create_regime_market_data("normal");

    let pred_1 = Uuid::new_v4();
    sqlx::query!(
        r#"
        INSERT INTO ensemble_predictions (
            id, symbol, ensemble_action, ensemble_signal, ensemble_confidence, disagreement_rate
        ) VALUES (
            $1, 'ES.FUT', 'BUY', 0.72, 0.80, 0.12
        )
        "#,
        pred_1,
    )
    .execute(&pool)
    .await
    .expect("Failed to insert prediction 1");

    // Step 2: Detect transition to Trending regime
    println!("  Step 2: Transition to Trending regime - Increase position size to 1.5x");
    let trending_data = create_regime_market_data("trending");

    let pred_2 = Uuid::new_v4();
    sqlx::query!(
        r#"
        INSERT INTO ensemble_predictions (
            id, symbol, ensemble_action, ensemble_signal, ensemble_confidence, disagreement_rate
        ) VALUES (
            $1, 'ES.FUT', 'BUY', 0.78, 0.85, 0.08
        )
        "#,
        pred_2,
    )
    .execute(&pool)
    .await
    .expect("Failed to insert prediction 2");

    // Step 3: Detect transition to Volatile regime
    println!("  Step 3: Transition to Volatile regime - Reduce position size to 0.5x");
    let volatile_data = create_regime_market_data("volatile");

    let pred_3 = Uuid::new_v4();
    sqlx::query!(
        r#"
        INSERT INTO ensemble_predictions (
            id, symbol, ensemble_action, ensemble_signal, ensemble_confidence, disagreement_rate
        ) VALUES (
            $1, 'ES.FUT', 'SELL', 0.65, 0.75, 0.20
        )
        "#,
        pred_3,
    )
    .execute(&pool)
    .await
    .expect("Failed to insert prediction 3");

    // Step 4: Detect transition to Crisis regime
    println!("  Step 4: Transition to Crisis regime - Reduce position size to 0.2x");
    let crisis_data = create_regime_market_data("crisis");

    let pred_4 = Uuid::new_v4();
    sqlx::query!(
        r#"
        INSERT INTO ensemble_predictions (
            id, symbol, ensemble_action, ensemble_signal, ensemble_confidence, disagreement_rate
        ) VALUES (
            $1, 'ES.FUT', 'SELL', 0.70, 0.80, 0.15
        )
        "#,
        pred_4,
    )
    .execute(&pool)
    .await
    .expect("Failed to insert prediction 4");

    // Verify regime transitions and position adjustments
    // RED PHASE: Expected to fail - full pipeline not yet implemented
    // GREEN PHASE: Will validate:
    // 1. Regime detection from market data
    // 2. Position size adjustments
    // 3. Stop-loss adjustments
    // 4. Regime logging to database
    // 5. Order metadata includes regime information

    println!("✗ RED: test_e2e_regime_adaptive_paper_trading - Not yet implemented");

    // Cleanup
    sqlx::query!(
        "DELETE FROM ensemble_predictions WHERE id IN ($1, $2, $3, $4)",
        pred_1,
        pred_2,
        pred_3,
        pred_4
    )
    .execute(&pool)
    .await
    .expect("Failed to cleanup test predictions");
}

// ============================================================================
// Helper: Extract Regime Features (Agent D13-D16)
// ============================================================================

/// Extract Wave D regime features from market data
///
/// This function will integrate with Wave D feature extraction modules:
/// - Agent D13: CUSUM Statistics (indices 201-210)
/// - Agent D14: ADX & Directional Indicators (indices 211-215)
/// - Agent D15: Regime Transition Probabilities (indices 216-220)
/// - Agent D16: Adaptive Strategy Metrics (indices 221-224)
fn extract_regime_features(market_data: &[(f64, f64, f64, f64, f64)]) -> HashMap<String, f64> {
    let mut features = HashMap::new();

    // Placeholder for Wave D feature extraction
    // RED PHASE: Stub implementation
    // GREEN PHASE: Will integrate with ml/src/features/regime_features.rs

    features.insert("regime_confidence".to_string(), 0.85);
    features.insert("cusum_statistic".to_string(), 0.0);
    features.insert("adx".to_string(), 25.0);
    features.insert("transition_probability".to_string(), 0.10);

    features
}

// ============================================================================
// Helper: Calculate Regime-Adjusted Position Size
// ============================================================================

/// Calculate position size adjusted for current market regime
///
/// Position size multipliers:
/// - Normal: 1.0x (base size)
/// - Trending: 1.5x (increase exposure in strong trends)
/// - Volatile: 0.5x (reduce exposure in choppy markets)
/// - Crisis: 0.2x (minimal exposure during extreme volatility)
fn calculate_regime_position_size(base_size: f64, regime: &str) -> f64 {
    let multiplier = match regime {
        "Normal" => 1.0,
        "Trending" => 1.5,
        "Volatile" => 0.5,
        "Crisis" => 0.2,
        _ => 1.0,
    };

    base_size * multiplier
}

// ============================================================================
// Helper: Calculate Regime-Adjusted Stop-Loss
// ============================================================================

/// Calculate stop-loss distance adjusted for current market regime
///
/// Stop-loss multipliers (ATR-based):
/// - Normal: 2.0x ATR (standard stop distance)
/// - Trending: 2.5x ATR (wider stop to avoid whipsaws)
/// - Volatile: 3.0x ATR (much wider stop for large swings)
/// - Crisis: 4.0x ATR (very wide stop for extreme volatility)
fn calculate_regime_stop_loss(atr: f64, regime: &str) -> f64 {
    let multiplier = match regime {
        "Normal" => 2.0,
        "Trending" => 2.5,
        "Volatile" => 3.0,
        "Crisis" => 4.0,
        _ => 2.0,
    };

    atr * multiplier
}
