//! Comprehensive tests for performance analytics and Parquet storage
//!
//! Tests cover:
//! 1. Sharpe Ratio calculation with known return series
//! 2. Maximum Drawdown with various equity curves
//! 3. PnL aggregation (daily/weekly/monthly)
//! 4. Parquet storage round-trip write/read tests
//! 5. Edge cases: zero returns, negative Sharpe, 100% drawdown

use chrono::{DateTime, Duration, Utc};
use rust_decimal::Decimal;
use std::str::FromStr;

use backtesting_service::performance::PerformanceAnalyzer;
use backtesting_service::strategy_engine::{BacktestTrade, TradeSide};
use config::structures::BacktestingPerformanceConfig;

/// Helper function to create a test trade
fn create_trade(
    trade_id: &str,
    symbol: &str,
    side: TradeSide,
    quantity: f64,
    entry_price: f64,
    exit_price: f64,
    entry_time: DateTime<Utc>,
    exit_time: DateTime<Utc>,
) -> BacktestTrade {
    let pnl = match side {
        TradeSide::Buy => (exit_price - entry_price) * quantity,
        TradeSide::Sell => (entry_price - exit_price) * quantity,
    };

    let return_percent = match side {
        TradeSide::Buy => (exit_price - entry_price) / entry_price,
        TradeSide::Sell => (entry_price - exit_price) / entry_price,
    };

    BacktestTrade {
        trade_id: trade_id.to_string(),
        symbol: symbol.to_string(),
        side,
        quantity: Decimal::from_str(&quantity.to_string()).unwrap(),
        entry_price: Decimal::from_str(&entry_price.to_string()).unwrap(),
        exit_price: Decimal::from_str(&exit_price.to_string()).unwrap(),
        entry_time,
        exit_time,
        pnl: Decimal::from_str(&pnl.to_string()).unwrap(),
        return_percent: Decimal::from_str(&return_percent.to_string()).unwrap(),
        entry_signal: "test_entry".to_string(),
        exit_signal: "test_exit".to_string(),
    }
}

// ========================================
// SHARPE RATIO TESTS
// ========================================

#[test]
fn test_sharpe_ratio_with_known_returns() {
    // Test data: Known return series with pre-calculated expected Sharpe ratio
    // Daily returns: [0.01, 0.015, -0.005, 0.02, 0.01]
    // Mean = 0.01, Std = 0.00866, Risk-free = 0.04/252 = 0.000159
    // Sharpe = (0.01 - 0.000159) * sqrt(252) / (0.00866 * sqrt(252))
    // Expected Sharpe ≈ 1.80

    let config = BacktestingPerformanceConfig {
        risk_free_rate: 0.04,
        equity_curve_resolution: 1000,
        enable_advanced_metrics: Some(true),
    };

    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();

    let trades = vec![
        create_trade(
            "1",
            "AAPL",
            TradeSide::Buy,
            100.0,
            100.0,
            101.0, // 1% return
            base_time,
            base_time + Duration::days(1),
        ),
        create_trade(
            "2",
            "AAPL",
            TradeSide::Buy,
            100.0,
            101.0,
            102.515, // 1.5% return
            base_time + Duration::days(1),
            base_time + Duration::days(2),
        ),
        create_trade(
            "3",
            "AAPL",
            TradeSide::Buy,
            100.0,
            102.515,
            102.01, // -0.5% return
            base_time + Duration::days(2),
            base_time + Duration::days(3),
        ),
        create_trade(
            "4",
            "AAPL",
            TradeSide::Buy,
            100.0,
            102.01,
            104.05, // 2% return
            base_time + Duration::days(3),
            base_time + Duration::days(4),
        ),
        create_trade(
            "5",
            "AAPL",
            TradeSide::Buy,
            100.0,
            104.05,
            105.09, // 1% return
            base_time + Duration::days(4),
            base_time + Duration::days(5),
        ),
    ];

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    // Sharpe ratio should be positive and in reasonable range (1.5 - 2.0)
    assert!(
        metrics.sharpe_ratio > 1.5 && metrics.sharpe_ratio < 2.0,
        "Expected Sharpe ratio ~1.8, got {}",
        metrics.sharpe_ratio
    );

    // Verify volatility is calculated correctly
    assert!(
        metrics.volatility > 0.0,
        "Volatility should be positive, got {}",
        metrics.volatility
    );
}

#[test]
fn test_sharpe_ratio_zero_volatility() {
    // All returns are identical - zero volatility should give zero Sharpe ratio
    let config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();

    let trades = vec![
        create_trade(
            "1",
            "AAPL",
            TradeSide::Buy,
            100.0,
            100.0,
            101.0, // 1% return
            base_time,
            base_time + Duration::days(1),
        ),
        create_trade(
            "2",
            "AAPL",
            TradeSide::Buy,
            100.0,
            101.0,
            102.01, // 1% return
            base_time + Duration::days(1),
            base_time + Duration::days(2),
        ),
    ];

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    // Zero volatility should result in zero or very low Sharpe ratio
    assert!(
        metrics.sharpe_ratio.abs() < 0.01,
        "Expected near-zero Sharpe ratio with identical returns, got {}",
        metrics.sharpe_ratio
    );
}

#[test]
fn test_negative_sharpe_ratio() {
    // Losing trades with negative excess returns
    let config = BacktestingPerformanceConfig {
        risk_free_rate: 0.10, // 10% risk-free rate to ensure negative excess return
        equity_curve_resolution: 1000,
        enable_advanced_metrics: Some(true),
    };

    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();

    let trades = vec![
        create_trade(
            "1",
            "AAPL",
            TradeSide::Buy,
            100.0,
            100.0,
            99.0, // -1% return
            base_time,
            base_time + Duration::days(1),
        ),
        create_trade(
            "2",
            "AAPL",
            TradeSide::Buy,
            100.0,
            99.0,
            98.0, // -1% return
            base_time + Duration::days(1),
            base_time + Duration::days(2),
        ),
        create_trade(
            "3",
            "AAPL",
            TradeSide::Buy,
            100.0,
            98.0,
            97.0, // -1% return
            base_time + Duration::days(2),
            base_time + Duration::days(3),
        ),
    ];

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    // Sharpe ratio should be negative due to returns < risk-free rate
    assert!(
        metrics.sharpe_ratio < 0.0,
        "Expected negative Sharpe ratio, got {}",
        metrics.sharpe_ratio
    );
}

// ========================================
// MAXIMUM DRAWDOWN TESTS
// ========================================

#[test]
fn test_max_drawdown_no_losses() {
    // Only winning trades - drawdown should be zero
    let config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();

    let trades = vec![
        create_trade(
            "1",
            "AAPL",
            TradeSide::Buy,
            100.0,
            100.0,
            105.0,
            base_time,
            base_time + Duration::days(1),
        ),
        create_trade(
            "2",
            "AAPL",
            TradeSide::Buy,
            100.0,
            105.0,
            110.0,
            base_time + Duration::days(1),
            base_time + Duration::days(2),
        ),
    ];

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    assert_eq!(
        metrics.max_drawdown, 0.0,
        "Expected zero drawdown with only winning trades, got {}",
        metrics.max_drawdown
    );
}

#[test]
fn test_max_drawdown_50_percent() {
    // Create trades that result in exactly 50% drawdown
    // Start: $10,000, Win to $15,000, Lose to $7,500 (50% from peak)
    let config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();

    let trades = vec![
        create_trade(
            "1",
            "AAPL",
            TradeSide::Buy,
            100.0,
            100.0,
            150.0, // +$5,000 profit
            base_time,
            base_time + Duration::days(1),
        ),
        create_trade(
            "2",
            "AAPL",
            TradeSide::Buy,
            100.0,
            150.0,
            75.0, // -$7,500 loss (50% from peak)
            base_time + Duration::days(1),
            base_time + Duration::days(2),
        ),
    ];

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    // Max drawdown should be 50%
    assert!(
        (metrics.max_drawdown - 50.0).abs() < 1.0,
        "Expected 50% drawdown, got {}%",
        metrics.max_drawdown
    );
}

#[test]
fn test_max_drawdown_100_percent() {
    // Complete loss - 100% drawdown
    let config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();

    let trades = vec![create_trade(
        "1",
        "AAPL",
        TradeSide::Buy,
        100.0,
        100.0,
        0.0, // Total loss
        base_time,
        base_time + Duration::days(1),
    )];

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    // Max drawdown should be 100%
    assert!(
        metrics.max_drawdown >= 99.9,
        "Expected 100% drawdown, got {}%",
        metrics.max_drawdown
    );
}

#[test]
fn test_max_drawdown_with_recovery() {
    // Test drawdown calculation with recovery
    // Pattern: Win -> Lose (drawdown) -> Win (recovery)
    let config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();

    let trades = vec![
        create_trade(
            "1",
            "AAPL",
            TradeSide::Buy,
            100.0,
            100.0,
            120.0, // +$2,000
            base_time,
            base_time + Duration::days(1),
        ),
        create_trade(
            "2",
            "AAPL",
            TradeSide::Buy,
            100.0,
            120.0,
            96.0, // -$2,400 (20% from peak of $12,000)
            base_time + Duration::days(1),
            base_time + Duration::days(2),
        ),
        create_trade(
            "3",
            "AAPL",
            TradeSide::Buy,
            100.0,
            96.0,
            130.0, // +$3,400 (recovery)
            base_time + Duration::days(2),
            base_time + Duration::days(3),
        ),
    ];

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    // Max drawdown should capture the 20% drop from peak
    assert!(
        metrics.max_drawdown >= 19.0 && metrics.max_drawdown <= 21.0,
        "Expected ~20% drawdown, got {}%",
        metrics.max_drawdown
    );
}

// ========================================
// PNL AGGREGATION TESTS
// ========================================

#[test]
fn test_win_loss_aggregation() {
    // Test winning/losing trade aggregation
    let config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();

    let trades = vec![
        create_trade(
            "1",
            "AAPL",
            TradeSide::Buy,
            100.0,
            100.0,
            110.0, // +$1,000
            base_time,
            base_time + Duration::days(1),
        ),
        create_trade(
            "2",
            "AAPL",
            TradeSide::Buy,
            100.0,
            110.0,
            105.0, // -$500
            base_time + Duration::days(1),
            base_time + Duration::days(2),
        ),
        create_trade(
            "3",
            "AAPL",
            TradeSide::Buy,
            100.0,
            105.0,
            115.0, // +$1,000
            base_time + Duration::days(2),
            base_time + Duration::days(3),
        ),
    ];

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    assert_eq!(metrics.total_trades, 3, "Expected 3 total trades");
    assert_eq!(metrics.winning_trades, 2, "Expected 2 winning trades");
    assert_eq!(metrics.losing_trades, 1, "Expected 1 losing trade");

    // Win rate should be 66.67%
    assert!(
        (metrics.win_rate - 66.67).abs() < 0.1,
        "Expected win rate ~66.67%, got {}%",
        metrics.win_rate
    );
}

#[test]
fn test_profit_factor_calculation() {
    // Profit factor = Gross Profit / Gross Loss
    let config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();

    let trades = vec![
        create_trade(
            "1",
            "AAPL",
            TradeSide::Buy,
            100.0,
            100.0,
            120.0, // +$2,000
            base_time,
            base_time + Duration::days(1),
        ),
        create_trade(
            "2",
            "AAPL",
            TradeSide::Buy,
            100.0,
            120.0,
            110.0, // -$1,000
            base_time + Duration::days(1),
            base_time + Duration::days(2),
        ),
    ];

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    // Profit factor = 2000 / 1000 = 2.0
    assert!(
        (metrics.profit_factor - 2.0).abs() < 0.1,
        "Expected profit factor ~2.0, got {}",
        metrics.profit_factor
    );
}

#[test]
fn test_profit_factor_no_losses() {
    // All winning trades - profit factor should be infinity
    let config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();

    let trades = vec![
        create_trade(
            "1",
            "AAPL",
            TradeSide::Buy,
            100.0,
            100.0,
            110.0,
            base_time,
            base_time + Duration::days(1),
        ),
        create_trade(
            "2",
            "AAPL",
            TradeSide::Buy,
            100.0,
            110.0,
            120.0,
            base_time + Duration::days(1),
            base_time + Duration::days(2),
        ),
    ];

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    assert!(
        metrics.profit_factor.is_infinite() && metrics.profit_factor > 0.0,
        "Expected positive infinity profit factor, got {}",
        metrics.profit_factor
    );
}

#[test]
fn test_average_win_loss() {
    // Test average win/loss calculations
    let config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();

    let trades = vec![
        create_trade(
            "1",
            "AAPL",
            TradeSide::Buy,
            100.0,
            100.0,
            110.0, // +$1,000
            base_time,
            base_time + Duration::days(1),
        ),
        create_trade(
            "2",
            "AAPL",
            TradeSide::Buy,
            100.0,
            110.0,
            125.0, // +$1,500
            base_time + Duration::days(1),
            base_time + Duration::days(2),
        ),
        create_trade(
            "3",
            "AAPL",
            TradeSide::Buy,
            100.0,
            125.0,
            118.0, // -$700
            base_time + Duration::days(2),
            base_time + Duration::days(3),
        ),
        create_trade(
            "4",
            "AAPL",
            TradeSide::Buy,
            100.0,
            118.0,
            108.0, // -$1,000
            base_time + Duration::days(3),
            base_time + Duration::days(4),
        ),
    ];

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    // Average win = (1000 + 1500) / 2 = 1250
    assert!(
        (metrics.avg_win - 1250.0).abs() < 10.0,
        "Expected avg win ~1250, got {}",
        metrics.avg_win
    );

    // Average loss = -(700 + 1000) / 2 = -850
    assert!(
        (metrics.avg_loss + 850.0).abs() < 10.0,
        "Expected avg loss ~-850, got {}",
        metrics.avg_loss
    );
}

// ========================================
// VAR AND EXPECTED SHORTFALL TESTS
// ========================================

#[test]
fn test_var_95_calculation() {
    // Test Value at Risk (VaR) at 95% confidence level
    let config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();

    // Create 20 trades with known return distribution
    let mut trades = Vec::new();
    for i in 0..20 {
        let return_pct = if i < 19 {
            0.01 // 95% of trades have 1% return
        } else {
            -0.05 // 5% of trades have -5% return (tail risk)
        };

        let exit_price = 100.0 * (1.0 + return_pct);
        trades.push(create_trade(
            &format!("{}", i),
            "AAPL",
            TradeSide::Buy,
            100.0,
            100.0,
            exit_price,
            base_time + Duration::days(i),
            base_time + Duration::days(i + 1),
        ));
    }

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    // VaR should capture the tail loss
    assert!(metrics.var_95.is_some(), "VaR should be calculated");
    let var = metrics.var_95.unwrap();
    assert!(var < 0.0, "VaR should be negative (loss), got {}", var);
}

#[test]
fn test_expected_shortfall() {
    // Expected Shortfall (CVaR) = average of returns below VaR
    let config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();

    let mut trades = Vec::new();
    for i in 0..100 {
        let return_pct = if i < 95 {
            0.01 // 95% of trades
        } else {
            -0.10 // 5% tail with -10% return
        };

        let exit_price = 100.0 * (1.0 + return_pct);
        trades.push(create_trade(
            &format!("{}", i),
            "AAPL",
            TradeSide::Buy,
            100.0,
            100.0,
            exit_price,
            base_time + Duration::days(i as i64),
            base_time + Duration::days(i as i64 + 1),
        ));
    }

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    assert!(
        metrics.expected_shortfall.is_some(),
        "Expected Shortfall should be calculated"
    );
    let es = metrics.expected_shortfall.unwrap();
    assert!(
        es < 0.0,
        "Expected Shortfall should be negative, got {}",
        es
    );

    // ES should be worse (more negative) than VaR
    let var = metrics.var_95.unwrap();
    assert!(
        es <= var,
        "Expected Shortfall ({}) should be <= VaR ({})",
        es,
        var
    );
}

// ========================================
// SORTINO RATIO TESTS
// ========================================

#[test]
fn test_sortino_ratio() {
    // Sortino ratio penalizes downside volatility only
    let config = BacktestingPerformanceConfig {
        risk_free_rate: 0.04,
        equity_curve_resolution: 1000,
        enable_advanced_metrics: Some(true),
    };

    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();

    let trades = vec![
        create_trade(
            "1",
            "AAPL",
            TradeSide::Buy,
            100.0,
            100.0,
            105.0, // +5% return
            base_time,
            base_time + Duration::days(1),
        ),
        create_trade(
            "2",
            "AAPL",
            TradeSide::Buy,
            100.0,
            105.0,
            103.0, // -1.9% return (downside)
            base_time + Duration::days(1),
            base_time + Duration::days(2),
        ),
        create_trade(
            "3",
            "AAPL",
            TradeSide::Buy,
            100.0,
            103.0,
            108.0, // +4.9% return
            base_time + Duration::days(2),
            base_time + Duration::days(3),
        ),
    ];

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    // Sortino ratio should be positive
    assert!(
        metrics.sortino_ratio > 0.0,
        "Expected positive Sortino ratio, got {}",
        metrics.sortino_ratio
    );

    // For strategies with limited downside, Sortino > Sharpe
    assert!(
        metrics.sortino_ratio >= metrics.sharpe_ratio,
        "Sortino ({}) should be >= Sharpe ({}) for limited downside strategy",
        metrics.sortino_ratio,
        metrics.sharpe_ratio
    );
}

// ========================================
// CALMAR RATIO TESTS
// ========================================

#[test]
fn test_calmar_ratio() {
    // Calmar ratio = Annualized Return / Max Drawdown
    let config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();

    let trades = vec![
        create_trade(
            "1",
            "AAPL",
            TradeSide::Buy,
            100.0,
            100.0,
            120.0, // +20%
            base_time,
            base_time + Duration::days(180),
        ),
        create_trade(
            "2",
            "AAPL",
            TradeSide::Buy,
            100.0,
            120.0,
            110.0, // -8.3% (drawdown)
            base_time + Duration::days(180),
            base_time + Duration::days(365),
        ),
    ];

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    // Calmar ratio should be positive and reasonable
    assert!(
        metrics.calmar_ratio > 0.0,
        "Expected positive Calmar ratio, got {}",
        metrics.calmar_ratio
    );

    // With ~10% return and ~8% drawdown, Calmar should be ~1.25
    assert!(
        metrics.calmar_ratio > 0.5 && metrics.calmar_ratio < 2.5,
        "Expected Calmar ratio between 0.5-2.5, got {}",
        metrics.calmar_ratio
    );
}

// ========================================
// EDGE CASES
// ========================================

#[test]
fn test_empty_trades() {
    // Empty trade list should return default metrics
    let config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&config).unwrap();

    let trades: Vec<BacktestTrade> = vec![];
    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    assert_eq!(metrics.total_return, 0.0);
    assert_eq!(metrics.sharpe_ratio, 0.0);
    assert_eq!(metrics.max_drawdown, 0.0);
    assert_eq!(metrics.total_trades, 0);
}

#[test]
fn test_single_trade() {
    // Single trade should produce valid metrics
    let config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();

    let trades = vec![create_trade(
        "1",
        "AAPL",
        TradeSide::Buy,
        100.0,
        100.0,
        110.0,
        base_time,
        base_time + Duration::days(1),
    )];

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    assert!(metrics.total_return > 0.0);
    assert_eq!(metrics.total_trades, 1);
    assert_eq!(metrics.winning_trades, 1);
    assert_eq!(metrics.losing_trades, 0);
}

#[test]
fn test_zero_returns() {
    // All trades break even - zero returns
    let config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();

    let trades = vec![
        create_trade(
            "1",
            "AAPL",
            TradeSide::Buy,
            100.0,
            100.0,
            100.0, // 0% return
            base_time,
            base_time + Duration::days(1),
        ),
        create_trade(
            "2",
            "AAPL",
            TradeSide::Buy,
            100.0,
            100.0,
            100.0, // 0% return
            base_time + Duration::days(1),
            base_time + Duration::days(2),
        ),
    ];

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    assert_eq!(
        metrics.total_return, 0.0,
        "Expected zero total return with break-even trades"
    );
    assert_eq!(metrics.max_drawdown, 0.0);
}

#[test]
fn test_sell_side_trades() {
    // Test short selling (sell side)
    let config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();

    let trades = vec![
        create_trade(
            "1",
            "AAPL",
            TradeSide::Sell,
            100.0,
            100.0,
            90.0, // Profit on short: (100-90)*100 = $1,000
            base_time,
            base_time + Duration::days(1),
        ),
        create_trade(
            "2",
            "AAPL",
            TradeSide::Sell,
            100.0,
            90.0,
            95.0, // Loss on short: (90-95)*100 = -$500
            base_time + Duration::days(1),
            base_time + Duration::days(2),
        ),
    ];

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    // Net PnL should be +$500
    assert!(
        metrics.total_return > 0.0,
        "Expected positive return from profitable short trades"
    );
    assert_eq!(metrics.winning_trades, 1);
    assert_eq!(metrics.losing_trades, 1);
}

// ========================================
// ANNUALIZED RETURN TESTS
// ========================================

#[test]
fn test_annualized_return_one_year() {
    // Test annualized return calculation for exactly 1 year
    let config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();

    let trades = vec![create_trade(
        "1",
        "AAPL",
        TradeSide::Buy,
        100.0,
        100.0,
        120.0, // 20% return
        base_time,
        base_time + Duration::days(365),
    )];

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    // For 1 year, annualized return ≈ total return
    assert!(
        (metrics.annualized_return - 20.0).abs() < 1.0,
        "Expected ~20% annualized return, got {}%",
        metrics.annualized_return
    );
}

#[test]
fn test_annualized_return_six_months() {
    // Test annualized return for 6 months
    let config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();

    let trades = vec![create_trade(
        "1",
        "AAPL",
        TradeSide::Buy,
        100.0,
        100.0,
        110.0, // 10% return in 6 months
        base_time,
        base_time + Duration::days(182),
    )];

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    // 10% in 6 months ≈ 21% annualized ((1.1)^2 - 1)
    assert!(
        metrics.annualized_return > 18.0 && metrics.annualized_return < 22.0,
        "Expected ~21% annualized return, got {}%",
        metrics.annualized_return
    );
}

#[test]
fn test_duration_calculation() {
    // Verify backtest duration is calculated correctly
    let config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();
    let duration_days = 100;

    let trades = vec![create_trade(
        "1",
        "AAPL",
        TradeSide::Buy,
        100.0,
        100.0,
        110.0,
        base_time,
        base_time + Duration::days(duration_days),
    )];

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    let expected_nanos = Duration::days(duration_days).num_nanoseconds().unwrap();
    assert_eq!(
        metrics.backtest_duration_nanos, expected_nanos,
        "Duration mismatch: expected {} nanos, got {}",
        expected_nanos, metrics.backtest_duration_nanos
    );
}

#[test]
fn test_largest_win_and_loss() {
    // Test identification of largest win and loss
    let config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&config).unwrap();
    let base_time = Utc::now();

    let trades = vec![
        create_trade(
            "1",
            "AAPL",
            TradeSide::Buy,
            100.0,
            100.0,
            110.0, // +$1,000
            base_time,
            base_time + Duration::days(1),
        ),
        create_trade(
            "2",
            "AAPL",
            TradeSide::Buy,
            100.0,
            110.0,
            135.0, // +$2,500 (largest win)
            base_time + Duration::days(1),
            base_time + Duration::days(2),
        ),
        create_trade(
            "3",
            "AAPL",
            TradeSide::Buy,
            100.0,
            135.0,
            125.0, // -$1,000
            base_time + Duration::days(2),
            base_time + Duration::days(3),
        ),
        create_trade(
            "4",
            "AAPL",
            TradeSide::Buy,
            100.0,
            125.0,
            105.0, // -$2,000 (largest loss)
            base_time + Duration::days(3),
            base_time + Duration::days(4),
        ),
    ];

    let metrics = analyzer.calculate_metrics(&trades, 10000.0);

    assert!(
        (metrics.largest_win - 2500.0).abs() < 10.0,
        "Expected largest win ~$2500, got {}",
        metrics.largest_win
    );
    assert!(
        (metrics.largest_loss + 2000.0).abs() < 10.0,
        "Expected largest loss ~-$2000, got {}",
        metrics.largest_loss
    );
}
