//! Comprehensive Risk Engine Tests
//!
//! Critical tests for pre-trade risk validation - PROTECTS TRADING CAPITAL
//! Tests position limits, margin calculations, and risk aggregation

use super::*;
use crate::risk_engine::VarEngine;
use config::structures::VarConfig;
use config::AssetClassificationConfig;
use rust_decimal::Decimal;
use rust_decimal::prelude::FromPrimitive;

// ============================================================================
// VaR Engine Tests - Marginal VaR Calculations
// ============================================================================

#[tokio::test]
async fn test_var_marginal_calculation_crypto() {
    let var_config = VarConfig {
        confidence_level: 0.95,
        time_horizon_days: 1,
        lookback_days: 252,
    };
    let asset_config = AssetClassificationConfig::default();
    let var_engine = VarEngine::new(var_config, asset_config);

    // BTC with 80% annual volatility
    let quantity = Decimal::from_f64(1.0).unwrap();
    let price = Decimal::from_f64(50000.0).unwrap();

    let marginal_var = var_engine
        .calculate_marginal_var("test_account", "BTC-USD", quantity, price)
        .await
        .unwrap();

    // BTC daily volatility ~5% (80% annual / sqrt(252))
    // VaR = $50,000 * 0.05 * 1.645 = ~$4,112
    assert!(marginal_var > Decimal::from(3000), "BTC VaR should reflect high volatility");
    assert!(marginal_var < Decimal::from(6000), "BTC VaR should be reasonable");
}

#[tokio::test]
async fn test_var_marginal_calculation_fx() {
    let var_config = VarConfig::default();
    let asset_config = AssetClassificationConfig::default();
    let var_engine = VarEngine::new(var_config, asset_config);

    // EUR/USD with 15% annual volatility
    let quantity = Decimal::from_f64(100000.0).unwrap();
    let price = Decimal::from_f64(1.10).unwrap();

    let marginal_var = var_engine
        .calculate_marginal_var("test_account", "EURUSD", quantity, price)
        .await
        .unwrap();

    // EURUSD daily volatility ~0.95% (15% annual / sqrt(252))
    // VaR = $110,000 * 0.0095 * 1.645 = ~$1,719
    assert!(marginal_var > Decimal::ZERO, "VaR should be positive");
    assert!(marginal_var < Decimal::from(3000), "FX VaR should be moderate");
}

#[tokio::test]
async fn test_var_marginal_calculation_blue_chip_stock() {
    let var_config = VarConfig::default();
    let asset_config = AssetClassificationConfig::default();
    let var_engine = VarEngine::new(var_config, asset_config);

    // AAPL with 25% annual volatility
    let quantity = Decimal::from_f64(100.0).unwrap();
    let price = Decimal::from_f64(180.0).unwrap();

    let marginal_var = var_engine
        .calculate_marginal_var("test_account", "AAPL", quantity, price)
        .await
        .unwrap();

    // AAPL daily volatility ~1.57% (25% annual / sqrt(252))
    // VaR = $18,000 * 0.0157 * 1.645 = ~$465
    assert!(marginal_var > Decimal::from(300), "Blue chip VaR should be meaningful");
    assert!(marginal_var < Decimal::from(800), "Blue chip VaR should be moderate");
}

#[tokio::test]
async fn test_var_marginal_calculation_general_equity() {
    let var_config = VarConfig::default();
    let asset_config = AssetClassificationConfig::default();
    let var_engine = VarEngine::new(var_config, asset_config);

    // Generic stock with 35% annual volatility
    let quantity = Decimal::from_f64(100.0).unwrap();
    let price = Decimal::from_f64(50.0).unwrap();

    let marginal_var = var_engine
        .calculate_marginal_var("test_account", "XYZ", quantity, price)
        .await
        .unwrap();

    // Generic equity daily volatility ~2.20% (35% annual / sqrt(252))
    // VaR = $5,000 * 0.022 * 1.645 = ~$181
    assert!(marginal_var > Decimal::from(100), "Generic equity VaR should be meaningful");
    assert!(marginal_var < Decimal::from(400), "Generic equity VaR should reflect higher volatility");
}

#[tokio::test]
async fn test_var_zero_position_error() {
    let var_config = VarConfig::default();
    let asset_config = AssetClassificationConfig::default();
    let var_engine = VarEngine::new(var_config, asset_config);

    let result = var_engine
        .calculate_marginal_var("test_account", "AAPL", Decimal::ZERO, Decimal::from(180))
        .await;

    assert!(result.is_err(), "Zero position should produce error (no risk)");
}

#[tokio::test]
async fn test_var_zero_price_error() {
    let var_config = VarConfig::default();
    let asset_config = AssetClassificationConfig::default();
    let var_engine = VarEngine::new(var_config, asset_config);

    let result = var_engine
        .calculate_marginal_var("test_account", "AAPL", Decimal::from(100), Decimal::ZERO)
        .await;

    assert!(result.is_err(), "Zero price should produce error");
}

#[tokio::test]
async fn test_var_small_position_proportional() {
    let var_config = VarConfig::default();
    let asset_config = AssetClassificationConfig::default();
    let var_engine = VarEngine::new(var_config, asset_config);

    // Small position should have proportionally small VaR (no artificial floor)
    let quantity = Decimal::from_f64(1.0).unwrap();
    let price = Decimal::from_f64(10.0).unwrap();

    let marginal_var = var_engine
        .calculate_marginal_var("test_account", "AAPL", quantity, price)
        .await
        .unwrap();

    // $10 position should have VaR < $5 (not artificially inflated)
    assert!(marginal_var > Decimal::ZERO);
    assert!(marginal_var < Decimal::from(5), "Small position VaR should be proportional");
}

#[tokio::test]
async fn test_var_large_position_scales() {
    let var_config = VarConfig::default();
    let asset_config = AssetClassificationConfig::default();
    let var_engine = VarEngine::new(var_config, asset_config);

    // Test VaR scaling with position size
    let small_quantity = Decimal::from_f64(100.0).unwrap();
    let large_quantity = Decimal::from_f64(1000.0).unwrap();
    let price = Decimal::from_f64(150.0).unwrap();

    let small_var = var_engine
        .calculate_marginal_var("test_account", "AAPL", small_quantity, price)
        .await
        .unwrap();

    let large_var = var_engine
        .calculate_marginal_var("test_account", "AAPL", large_quantity, price)
        .await
        .unwrap();

    // VaR should scale roughly linearly with position size
    let ratio = large_var / small_var;
    assert!(ratio > Decimal::from_f64(8.0).unwrap(), "Large position VaR should scale");
    assert!(ratio < Decimal::from_f64(12.0).unwrap(), "VaR scaling should be roughly linear");
}

// ============================================================================
// Volatility Classification Tests
// ============================================================================

#[tokio::test]
async fn test_var_crypto_higher_than_equity() {
    let var_config = VarConfig::default();
    let asset_config = AssetClassificationConfig::default();
    let var_engine = VarEngine::new(var_config, asset_config);

    let quantity = Decimal::from_f64(100.0).unwrap();
    let price = Decimal::from_f64(100.0).unwrap();

    let crypto_var = var_engine
        .calculate_marginal_var("test_account", "BTC-USD", quantity, price)
        .await
        .unwrap();

    let equity_var = var_engine
        .calculate_marginal_var("test_account", "AAPL", quantity, price)
        .await
        .unwrap();

    assert!(crypto_var > equity_var, "Crypto VaR should exceed equity VaR due to higher volatility");
}

#[tokio::test]
async fn test_var_equity_higher_than_fx() {
    let var_config = VarConfig::default();
    let asset_config = AssetClassificationConfig::default();
    let var_engine = VarEngine::new(var_config, asset_config);

    let quantity = Decimal::from_f64(100.0).unwrap();
    let price = Decimal::from_f64(100.0).unwrap();

    let equity_var = var_engine
        .calculate_marginal_var("test_account", "MSFT", quantity, price)
        .await
        .unwrap();

    let fx_var = var_engine
        .calculate_marginal_var("test_account", "EURUSD", quantity, price)
        .await
        .unwrap();

    assert!(equity_var > fx_var, "Equity VaR should exceed FX VaR due to higher volatility");
}

// ============================================================================
// Edge Cases and Boundary Conditions
// ============================================================================

#[tokio::test]
async fn test_var_maximum_position_value() {
    let var_config = VarConfig::default();
    let asset_config = AssetClassificationConfig::default();
    let var_engine = VarEngine::new(var_config, asset_config);

    // Very large position
    let quantity = Decimal::from_f64(1000000.0).unwrap();
    let price = Decimal::from_f64(100.0).unwrap();

    let result = var_engine
        .calculate_marginal_var("test_account", "AAPL", quantity, price)
        .await;

    assert!(result.is_ok(), "Should handle large positions");
    assert!(result.unwrap() > Decimal::ZERO, "VaR should be meaningful for large positions");
}

#[tokio::test]
async fn test_var_fractional_shares() {
    let var_config = VarConfig::default();
    let asset_config = AssetClassificationConfig::default();
    let var_engine = VarEngine::new(var_config, asset_config);

    // Fractional position
    let quantity = Decimal::from_f64(0.5).unwrap();
    let price = Decimal::from_f64(180.0).unwrap();

    let marginal_var = var_engine
        .calculate_marginal_var("test_account", "AAPL", quantity, price)
        .await
        .unwrap();

    assert!(marginal_var > Decimal::ZERO);
    assert!(marginal_var < Decimal::from(50), "Fractional position should have small VaR");
}

#[tokio::test]
async fn test_var_negative_quantity_error() {
    let var_config = VarConfig::default();
    let asset_config = AssetClassificationConfig::default();
    let var_engine = VarEngine::new(var_config, asset_config);

    let result = var_engine
        .calculate_marginal_var("test_account", "AAPL", Decimal::from(-100), Decimal::from(180))
        .await;

    // Should handle negative quantity (short position) OR reject
    // Either behavior is acceptable depending on implementation
    if let Ok(var_value) = result {
        assert!(var_value > Decimal::ZERO, "Negative quantity VaR should still be positive risk");
    }
}

#[tokio::test]
async fn test_var_unknown_symbol_uses_default_volatility() {
    let var_config = VarConfig::default();
    let asset_config = AssetClassificationConfig::default();
    let var_engine = VarEngine::new(var_config, asset_config);

    // Unknown symbol should use default volatility
    let quantity = Decimal::from_f64(100.0).unwrap();
    let price = Decimal::from_f64(50.0).unwrap();

    let result = var_engine
        .calculate_marginal_var("test_account", "UNKNOWN_XYZ123", quantity, price)
        .await;

    assert!(result.is_ok(), "Should handle unknown symbols with default volatility");
    let var_value = result.unwrap();
    assert!(var_value > Decimal::ZERO);
}

// ============================================================================
// Multiple Asset Tests
// ============================================================================

#[tokio::test]
async fn test_var_multiple_concurrent_calculations() {
    let var_config = VarConfig::default();
    let asset_config = AssetClassificationConfig::default();
    let var_engine = VarEngine::new(var_config, asset_config);

    let quantity = Decimal::from_f64(100.0).unwrap();
    let price = Decimal::from_f64(100.0).unwrap();

    // Calculate VaR for multiple assets concurrently
    let symbols = vec!["AAPL", "MSFT", "GOOGL", "TSLA"];
    let mut handles = vec![];

    for symbol in symbols {
        let engine_ref = &var_engine;
        let handle = tokio::spawn(async move {
            engine_ref.calculate_marginal_var("test_account", symbol, quantity, price).await
        });
        handles.push(handle);
    }

    for handle in handles {
        let result = handle.await.unwrap();
        assert!(result.is_ok(), "Concurrent VaR calculations should succeed");
    }
}

// ============================================================================
// Configuration Tests
// ============================================================================

#[tokio::test]
async fn test_var_different_confidence_levels() {
    // 95% confidence
    let var_config_95 = VarConfig {
        confidence_level: 0.95,
        time_horizon_days: 1,
        lookback_days: 252,
    };
    let var_engine_95 = VarEngine::with_defaults(var_config_95);

    // 99% confidence
    let var_config_99 = VarConfig {
        confidence_level: 0.99,
        time_horizon_days: 1,
        lookback_days: 252,
    };
    let var_engine_99 = VarEngine::with_defaults(var_config_99);

    let quantity = Decimal::from_f64(100.0).unwrap();
    let price = Decimal::from_f64(150.0).unwrap();

    let var_95 = var_engine_95
        .calculate_marginal_var("test_account", "AAPL", quantity, price)
        .await
        .unwrap();

    let var_99 = var_engine_99
        .calculate_marginal_var("test_account", "AAPL", quantity, price)
        .await
        .unwrap();

    assert!(var_99 > var_95, "99% VaR should exceed 95% VaR (higher confidence = more conservative)");
}

#[tokio::test]
async fn test_var_precision_no_rounding_artifacts() {
    let var_config = VarConfig::default();
    let asset_config = AssetClassificationConfig::default();
    let var_engine = VarEngine::new(var_config, asset_config);

    // Test for rounding/precision issues
    let quantity = Decimal::from_f64(137.89).unwrap();
    let price = Decimal::from_f64(175.43).unwrap();

    let result = var_engine
        .calculate_marginal_var("test_account", "AAPL", quantity, price)
        .await;

    assert!(result.is_ok(), "Should handle decimal precision correctly");
}
