//! Comprehensive test suite for asset classification system
//!
//! Tests cover pattern matching, database integration, trading parameters,
//! volatility profiling, and ConfigManager integration.
#![allow(unused_crate_dependencies)]

use chrono::Utc;
use config::asset_classification_integration::MarketCapTier;
use config::{
    create_default_configurations, manager::ConfigManagerBuilder, AssetClass,
    AssetClassificationManager, AssetConfig, CryptoType, DetailedVolatilityProfile, EquitySector,
    ExecutionConfig, ForexPairType, GeographicRegion, JumpRiskProfile, OrderType, PositionLimits,
    RiskThresholds, ServiceConfig, SettlementConfig, TimeInForce, TradingParameters,
};
use rust_decimal::Decimal;
use std::str::FromStr;
use uuid::Uuid;

#[tokio::test]
async fn test_asset_classification_manager_creation() {
    let manager = AssetClassificationManager::new();

    // Test initial state
    assert_eq!(manager.get_active_configurations().len(), 0);
    // Initially no configurations loaded, so classification may be unknown
}

#[tokio::test]
async fn test_default_configurations_loading() {
    let mut manager = AssetClassificationManager::new();
    let configs = create_default_configurations();

    assert!(
        !configs.is_empty(),
        "Default configurations should not be empty"
    );

    manager.load_configurations(configs).await.unwrap();

    // Test that configurations were loaded
    assert!(!manager.get_active_configurations().is_empty());
}

#[tokio::test]
async fn test_symbol_classification() {
    let mut manager = AssetClassificationManager::new();
    let configs = create_default_configurations();
    manager.load_configurations(configs).await.unwrap();

    // Test blue chip equity classification
    let aapl_class = manager.classify_symbol("AAPL");
    match aapl_class {
        AssetClass::Equity {
            sector: EquitySector::Technology,
            ..
        } => {}
        _ => panic!("AAPL should be classified as Technology equity"),
    }

    // Test crypto classification
    let btc_class = manager.classify_symbol("BTCUSD");
    match btc_class {
        AssetClass::Crypto {
            crypto_type: CryptoType::Bitcoin,
            ..
        } => {}
        _ => panic!("BTCUSD should be classified as Bitcoin crypto"),
    }

    // Test forex classification
    let eur_class = manager.classify_symbol("EURUSD");
    match eur_class {
        AssetClass::Forex {
            pair_type: ForexPairType::Major,
            ..
        } => {}
        _ => panic!("EURUSD should be classified as Major forex pair"),
    }

    // Test unknown symbol
    assert_eq!(
        manager.classify_symbol("UNKNOWN_SYMBOL"),
        AssetClass::Unknown
    );
}

#[tokio::test]
async fn test_volatility_profiles() {
    let mut manager = AssetClassificationManager::new();
    let configs = create_default_configurations();
    manager.load_configurations(configs).await.unwrap();

    // Test AAPL volatility
    let aapl_vol = manager.get_daily_volatility("AAPL");
    assert!(aapl_vol > 0.0, "AAPL should have positive volatility");
    assert!(aapl_vol < 0.1, "AAPL daily volatility should be reasonable");

    let aapl_profile = manager.get_volatility_profile("AAPL");
    assert!(
        aapl_profile.is_some(),
        "AAPL should have volatility profile"
    );

    if let Some(profile) = aapl_profile {
        assert!(profile.base_annual_volatility > 0.0);
        assert!(profile.stress_volatility_multiplier >= 1.0);
        assert!(profile.jump_risk.jump_probability >= 0.0);
        assert!(profile.jump_risk.jump_probability <= 1.0);
    }

    // Test crypto has higher volatility than equity
    let btc_vol = manager.get_daily_volatility("BTCUSD");
    assert!(
        btc_vol > aapl_vol,
        "Crypto should have higher volatility than equity"
    );
}

#[tokio::test]
async fn test_trading_parameters() {
    let mut manager = AssetClassificationManager::new();
    let configs = create_default_configurations();
    manager.load_configurations(configs).await.unwrap();

    // Test AAPL trading parameters
    let aapl_params = manager.get_trading_parameters("AAPL");
    assert!(aapl_params.is_some(), "AAPL should have trading parameters");

    if let Some(params) = aapl_params {
        assert!(params.position_limits.max_position_fraction > 0.0);
        assert!(params.position_limits.max_position_fraction <= 1.0);
        assert!(params.position_limits.max_leverage >= 1.0);
        assert!(params.risk_thresholds.daily_loss_limit > 0.0);
        assert!(!params.execution_config.preferred_order_types.is_empty());
    }
}

#[tokio::test]
async fn test_position_size_recommendations() {
    let mut manager = AssetClassificationManager::new();
    let configs = create_default_configurations();
    manager.load_configurations(configs).await.unwrap();

    let portfolio_nav = Decimal::from_str("1000000.00").unwrap(); // $1M

    // Test AAPL position sizing
    let aapl_size = manager.get_position_size_recommendation("AAPL", portfolio_nav);
    assert!(
        aapl_size.is_some(),
        "Should get position size recommendation for AAPL"
    );

    if let Some(size) = aapl_size {
        assert!(size > Decimal::ZERO, "Position size should be positive");
        assert!(
            size <= portfolio_nav,
            "Position size should not exceed portfolio NAV"
        );
    }

    // Test that crypto has smaller recommended position than equity
    let btc_size = manager.get_position_size_recommendation("BTCUSD", portfolio_nav);
    if let (Some(aapl), Some(btc)) = (aapl_size, btc_size) {
        assert!(
            btc < aapl,
            "Crypto position should be smaller than equity due to higher risk"
        );
    }
}

#[tokio::test]
async fn test_trading_hours() {
    let mut manager = AssetClassificationManager::new();
    let configs = create_default_configurations();
    manager.load_configurations(configs).await.unwrap();

    let timestamp = Utc::now();

    // Test equity trading hours (should have restrictions)
    let _aapl_active = manager.is_trading_active("AAPL", timestamp);

    // Test crypto trading hours (should be 24/7)
    let btc_active = manager.is_trading_active("BTCUSD", timestamp);
    assert!(btc_active, "Crypto should trade 24/7");

    // Note: AAPL result depends on current time, but should not panic
    // This tests the mechanism works
}

#[tokio::test]
async fn test_custom_asset_configuration() {
    let mut manager = AssetClassificationManager::new();

    // Create custom configuration
    let custom_config = create_test_configuration();
    let configs = vec![custom_config];

    manager.load_configurations(configs).await.unwrap();

    // Test that custom configuration works
    let test_class = manager.classify_symbol("TESTSTOCK");
    match test_class {
        AssetClass::Equity {
            sector: EquitySector::Technology,
            market_cap: MarketCapTier::SmallCap,
            ..
        } => {}
        _ => panic!("TESTSTOCK should match custom configuration"),
    }

    // Test parameters
    let params = manager.get_trading_parameters("TESTSTOCK");
    assert!(
        params.is_some(),
        "Custom configuration should have trading parameters"
    );
}

#[tokio::test]
async fn test_pattern_priority() {
    let mut manager = AssetClassificationManager::new();

    // Create configurations with different priorities
    let high_priority = create_priority_test_config("^TEST.*$", 100);
    let low_priority = create_priority_test_config("^TEST.*$", 50);

    let configs = vec![low_priority, high_priority]; // Load in reverse priority order
    manager.load_configurations(configs).await.unwrap();

    // Should match high priority configuration
    let test_class = manager.classify_symbol("TESTPATTERN");
    match test_class {
        AssetClass::Equity {
            market_cap: MarketCapTier::LargeCap,
            ..
        } => {}
        _ => panic!("Should match high priority configuration"),
    }
}

#[tokio::test]
async fn test_config_manager_integration() {
    let mut asset_manager = AssetClassificationManager::new();
    let configs = create_default_configurations();
    asset_manager.load_configurations(configs).await.unwrap();

    let service_config = ServiceConfig {
        name: "test_service".to_string(),
        environment: "test".to_string(),
        version: "1.0.0".to_string(),
        settings: serde_json::json!({}),
    };

    let config_manager = ConfigManagerBuilder::new(service_config)
        .with_asset_classification(asset_manager)
        .build();

    // Test integration methods
    let asset_class = config_manager.classify_symbol("AAPL");
    assert_ne!(asset_class, AssetClass::Unknown);

    let daily_vol = config_manager.get_daily_volatility("AAPL");
    assert!(daily_vol > 0.0);

    let params = config_manager.get_trading_parameters("AAPL");
    assert!(params.is_some());

    let portfolio_nav = Decimal::from_str("100000.00").unwrap();
    let position_size = config_manager.get_position_size_recommendation("AAPL", portfolio_nav);
    assert!(position_size.is_some());
}

#[tokio::test]
async fn test_cache_functionality() {
    let service_config = ServiceConfig {
        name: "test_service".to_string(),
        environment: "test".to_string(),
        version: "1.0.0".to_string(),
        settings: serde_json::json!({}),
    };

    let config_manager = ConfigManagerBuilder::new(service_config)
        .with_cache_timeout(std::time::Duration::from_secs(1))
        .build();

    // Test cache set/get
    let test_value = serde_json::json!({"test": "value"});
    config_manager.set_cached_config("test_key".to_string(), test_value.clone());

    let cached = config_manager.get_cached_config("test_key");
    assert_eq!(cached, Some(test_value));

    // Test cache expiration
    tokio::time::sleep(std::time::Duration::from_secs(2)).await;
    let expired = config_manager.get_cached_config("test_key");
    assert_eq!(expired, None);
}

#[tokio::test]
async fn test_configuration_validation() {
    let manager = AssetClassificationManager::new();

    // Test with invalid regex pattern
    let invalid_config = AssetConfig {
        id: Uuid::new_v4(),
        name: "Invalid Pattern".to_string(),
        symbol_pattern: "[invalid_regex".to_string(), // Invalid regex
        compiled_pattern: None,
        asset_class: AssetClass::Unknown,
        volatility_profile: create_default_volatility_profile(),
        trading_parameters: create_default_trading_parameters(),
        priority: 100,
        is_active: true,
        created_at: Utc::now(),
        updated_at: Utc::now(),
        trading_hours: None,
        settlement_config: SettlementConfig {
            settlement_days: 2,
            settlement_currency: "USD".to_string(),
            physical_settlement: false,
        },
    };

    // Should handle invalid configuration gracefully
    let mut test_manager = manager;
    let result = test_manager.load_configurations(vec![invalid_config]).await;
    assert!(
        result.is_ok(),
        "Should handle invalid configurations gracefully"
    );
}

// Helper functions for test configurations

fn create_test_configuration() -> AssetConfig {
    let now = Utc::now();

    AssetConfig {
        id: Uuid::new_v4(),
        name: "Test Configuration".to_string(),
        symbol_pattern: "^TESTSTOCK$".to_string(),
        compiled_pattern: None,
        asset_class: AssetClass::Equity {
            sector: EquitySector::Technology,
            market_cap: MarketCapTier::SmallCap,
            region: GeographicRegion::NorthAmerica,
        },
        volatility_profile: create_default_volatility_profile(),
        trading_parameters: create_default_trading_parameters(),
        priority: 100,
        is_active: true,
        created_at: now,
        updated_at: now,
        trading_hours: None,
        settlement_config: SettlementConfig {
            settlement_days: 2,
            settlement_currency: "USD".to_string(),
            physical_settlement: false,
        },
    }
}

fn create_priority_test_config(pattern: &str, priority: u32) -> AssetConfig {
    let now = Utc::now();
    let market_cap = if priority > 75 {
        MarketCapTier::LargeCap
    } else {
        MarketCapTier::SmallCap
    };

    AssetConfig {
        id: Uuid::new_v4(),
        name: format!("Priority {} Configuration", priority),
        symbol_pattern: pattern.to_string(),
        compiled_pattern: None,
        asset_class: AssetClass::Equity {
            sector: EquitySector::Technology,
            market_cap,
            region: GeographicRegion::NorthAmerica,
        },
        volatility_profile: create_default_volatility_profile(),
        trading_parameters: create_default_trading_parameters(),
        priority,
        is_active: true,
        created_at: now,
        updated_at: now,
        trading_hours: None,
        settlement_config: SettlementConfig {
            settlement_days: 2,
            settlement_currency: "USD".to_string(),
            physical_settlement: false,
        },
    }
}

fn create_default_volatility_profile() -> DetailedVolatilityProfile {
    DetailedVolatilityProfile {
        base_annual_volatility: 0.25,
        stress_volatility_multiplier: 2.0,
        intraday_pattern: vec![1.0; 24],
        volatility_persistence: 0.85,
        jump_risk: JumpRiskProfile {
            jump_probability: 0.02,
            jump_magnitude: 0.05,
            max_jump_size: 0.15,
        },
    }
}

fn create_default_trading_parameters() -> TradingParameters {
    TradingParameters {
        position_limits: PositionLimits {
            max_position_fraction: 0.10,
            max_leverage: 2.0,
            concentration_limit: 0.20,
            min_position_size: Decimal::from(100),
        },
        risk_thresholds: RiskThresholds {
            var_limit: 0.05,
            daily_loss_limit: 0.03,
            stop_loss_threshold: 0.10,
            volatility_circuit_breaker: 0.05,
            max_drawdown_threshold: 0.15,
        },
        execution_config: ExecutionConfig {
            preferred_order_types: vec![OrderType::Limit, OrderType::Market],
            tick_size: Decimal::from_str("0.01").unwrap(),
            min_order_size: Decimal::from(1),
            max_order_size: Decimal::from(10000),
            time_in_force_default: TimeInForce::Day,
            slippage_tolerance: 0.001,
        },
        market_making: None,
    }
}

#[tokio::test]
async fn test_comprehensive_workflow() {
    // This test demonstrates a complete workflow
    println!("🧪 Running comprehensive asset classification workflow test");

    // 1. Initialize manager
    let mut manager = AssetClassificationManager::new();

    // 2. Load configurations
    let configs = create_default_configurations();
    manager.load_configurations(configs).await.unwrap();

    // 3. Test multiple symbols
    let symbols = vec!["AAPL", "MSFT", "BTCUSD", "EURUSD", "UNKNOWN"];

    for symbol in symbols {
        let asset_class = manager.classify_symbol(symbol);
        let daily_vol = manager.get_daily_volatility(symbol);
        let trading_params = manager.get_trading_parameters(symbol);

        println!(
            "Symbol: {} | Class: {:?} | Daily Vol: {:.2}% | Has Params: {}",
            symbol,
            asset_class,
            daily_vol * 100.0,
            trading_params.is_some()
        );
    }

    // 4. Test position sizing
    let portfolio_nav = Decimal::from_str("500000.00").unwrap();
    for symbol in ["AAPL", "BTCUSD"] {
        if let Some(size) = manager.get_position_size_recommendation(symbol, portfolio_nav) {
            let percentage = (size / portfolio_nav) * Decimal::from(100);
            println!(
                "Recommended position for {}: ${} ({:.1}%)",
                symbol, size, percentage
            );
        }
    }

    println!("✅ Comprehensive workflow test completed successfully");
}
