// Disabled: register_strategy() and StrategyExecutor::name() were removed during refactoring.
// These tests need to be rewritten to use the current StrategyEngine API.
#![allow(unexpected_cfgs, unused, dead_code, clippy::all)]
#![cfg(feature = "disabled_ma_crossover_tests")]
//! Moving Average Crossover Strategy Multi-Symbol Backtests
//!
//! Comprehensive backtesting of MA crossover strategy across 5 diverse symbols:
//! - ES.FUT (E-mini S&P 500) - Equity index futures
//! - NQ.FUT (E-mini NASDAQ) - Tech index futures
//! - GC (Gold) - Commodity futures
//! - ZN.FUT (10-Year Treasury) - Fixed income futures
//! - 6E.FUT (Euro FX) - Currency futures
//!
//! Strategy Parameters:
//! - Fast MA: 10 periods
//! - Slow MA: 50 periods
//! - Signal: Buy when fast > slow, Sell when fast < slow

use anyhow::Result;
use chrono::{DateTime, Utc};
use rust_decimal::prelude::ToPrimitive;
use rust_decimal::Decimal;
use std::collections::HashMap;
use std::sync::Arc;

mod mock_repositories;

use backtesting_service::dbn_repository::DbnMarketDataRepository;
use backtesting_service::performance::{PerformanceAnalyzer, PerformanceMetrics};
use backtesting_service::repositories::{
    BacktestingRepositories, MarketDataRepository, NewsRepository, TradingRepository,
};
use backtesting_service::service::BacktestContext;
use backtesting_service::strategy_engine::{
    MarketData, StrategyEngine, StrategyExecutor, TimeFrame, TradeSide, TradeSignal,
};
use config::structures::BacktestingPerformanceConfig;
use config::structures::BacktestingStrategyConfig;
use mock_repositories::*;

/// Helper to get multi-symbol file mappings
fn get_multi_symbol_file_mapping() -> HashMap<String, String> {
    let root = mock_repositories::get_project_root();
    let mut mapping = HashMap::new();

    // Equity indices
    mapping.insert(
        "ES.FUT".to_string(),
        format!(
            "{}/test_data/real/databento/ES.FUT_ohlcv-1m_2024-01-02.dbn",
            root
        ),
    );
    mapping.insert(
        "NQ.FUT".to_string(),
        format!(
            "{}/test_data/real/databento/NQ.FUT_ohlcv-1m_2024-01-02.dbn",
            root
        ),
    );

    // Commodities (Gold)
    mapping.insert(
        "GC".to_string(),
        format!("{}/test_data/real/databento/GC_continuous_ohlcv-1m_2024-01-02_to_2024-01-31.uncompressed.dbn", root),
    );

    // Fixed income (Treasuries)
    mapping.insert(
        "ZN.FUT".to_string(),
        format!(
            "{}/test_data/real/databento/ZN.FUT_ohlcv-1m_2024-01-02_to_2024-01-31.uncompressed.dbn",
            root
        ),
    );

    // Currencies (Euro FX)
    mapping.insert(
        "6E.FUT".to_string(),
        format!(
            "{}/test_data/real/databento/6E.FUT_ohlcv-1m_2024-01-02_to_2024-01-31.uncompressed.dbn",
            root
        ),
    );

    mapping
}

/// Real Moving Average Crossover Strategy with proper technical analysis
#[derive(Debug)]
struct RealMaCrossoverStrategy {
    fast_period: usize,
    slow_period: usize,
    price_history: std::sync::RwLock<HashMap<String, Vec<f64>>>,
}

impl RealMaCrossoverStrategy {
    fn new(fast_period: usize, slow_period: usize) -> Self {
        Self {
            fast_period,
            slow_period,
            price_history: std::sync::RwLock::new(HashMap::new()),
        }
    }

    fn calculate_sma(prices: &[f64], period: usize) -> Option<f64> {
        if prices.len() < period {
            return None;
        }

        let sum: f64 = prices.iter().rev().take(period).sum();
        Some(sum / period as f64)
    }
}

impl StrategyExecutor for RealMaCrossoverStrategy {
    fn execute(
        &self,
        market_data: &MarketData,
        portfolio: &backtesting_service::strategy_engine::Portfolio,
        _parameters: &HashMap<String, String>,
    ) -> Result<Vec<TradeSignal>> {
        let mut signals = Vec::new();

        // Update price history
        let current_price = market_data.close.to_f64().unwrap_or(0.0);
        {
            let mut history = self.price_history.write().expect("INVARIANT: RwLock should not be poisoned");
            let prices = history
                .entry(market_data.symbol.clone())
                .or_insert_with(Vec::new);
            prices.push(current_price);
        }

        // Read price history
        let history = self.price_history.read().expect("INVARIANT: RwLock should not be poisoned");
        let prices = history.get(&market_data.symbol);

        if let Some(prices) = prices {
            // Need enough data for slow MA
            if prices.len() < self.slow_period {
                return Ok(signals);
            }

            // Calculate MAs
            let fast_ma = Self::calculate_sma(prices, self.fast_period);
            let slow_ma = Self::calculate_sma(prices, self.slow_period);

            if let (Some(fast), Some(slow)) = (fast_ma, slow_ma) {
                // Get previous MAs for crossover detection
                if prices.len() > self.slow_period {
                    let prev_prices = &prices[..prices.len() - 1];
                    let prev_fast_ma = Self::calculate_sma(prev_prices, self.fast_period);
                    let prev_slow_ma = Self::calculate_sma(prev_prices, self.slow_period);

                    if let (Some(prev_fast), Some(prev_slow)) = (prev_fast_ma, prev_slow_ma) {
                        let position = portfolio.get_position(&market_data.symbol);

                        // Bullish crossover: fast crosses above slow
                        if prev_fast <= prev_slow && fast > slow && position.is_none() {
                            // Calculate position size (10% of capital per position)
                            let allocation = 0.10;
                            let cash = portfolio.cash().to_f64().unwrap_or(0.0);
                            let position_value = cash * allocation;
                            let quantity = Decimal::from_f64_retain(position_value / current_price)
                                .unwrap_or(Decimal::ZERO);

                            if quantity > Decimal::ZERO {
                                signals.push(TradeSignal {
                                    symbol: market_data.symbol.clone(),
                                    side: TradeSide::Buy,
                                    quantity,
                                    strength: Decimal::from_f64_retain(0.85)
                                        .unwrap_or(Decimal::ZERO),
                                    reason: format!(
                                        "MA Crossover BUY: fast={:.2} > slow={:.2}",
                                        fast, slow
                                    ),
                                    features: None,
                                    news_events: None,
                                });
                            }
                        }
                        // Bearish crossover: fast crosses below slow
                        else if prev_fast >= prev_slow && fast < slow && position.is_some() {
                            if let Some(pos) = position {
                                signals.push(TradeSignal {
                                    symbol: market_data.symbol.clone(),
                                    side: TradeSide::Sell,
                                    quantity: pos.quantity,
                                    strength: Decimal::from_f64_retain(0.85)
                                        .unwrap_or(Decimal::ZERO),
                                    reason: format!(
                                        "MA Crossover SELL: fast={:.2} < slow={:.2}",
                                        fast, slow
                                    ),
                                    features: None,
                                    news_events: None,
                                });
                            }
                        }
                    }
                }
            }
        }

        Ok(signals)
    }

    fn name(&self) -> &str {
        "ma_crossover_10_50"
    }
}

/// Create repositories with DBN data source
async fn create_repositories() -> Result<Arc<dyn BacktestingRepositories>> {
    let file_mapping = get_multi_symbol_file_mapping();
    let market_data_repo = Box::new(DbnMarketDataRepository::new(file_mapping).await?)
        as Box<dyn MarketDataRepository>;
    let trading_repo = Box::new(MockTradingRepository::new()) as Box<dyn TradingRepository>;
    let news_repo = Box::new(MockNewsRepository::new()) as Box<dyn NewsRepository>;

    Ok(Arc::new(MockBacktestingRepositories::new(
        market_data_repo,
        trading_repo,
        news_repo,
    )))
}

/// Helper to run backtest for a symbol
async fn run_backtest_for_symbol(
    symbol: &str,
    initial_capital: f64,
) -> Result<(
    Vec<backtesting_service::strategy_engine::BacktestTrade>,
    PerformanceMetrics,
)> {
    let repositories = create_repositories().await?;

    // Create custom strategy engine with MA crossover
    let config = BacktestingStrategyConfig::default();
    let mut engine = StrategyEngine::new(&config, repositories.clone()).await?;

    // Register custom MA strategy
    let ma_strategy = Box::new(RealMaCrossoverStrategy::new(10, 50));
    engine.register_strategy("ma_crossover_10_50".to_string(), ma_strategy);

    // Backtest period: Jan 2-3, 2024 (using available data)
    let start_time = DateTime::parse_from_rfc3339("2024-01-02T00:00:00Z")?.with_timezone(&Utc);
    let end_time = DateTime::parse_from_rfc3339("2024-01-03T00:00:00Z")?.with_timezone(&Utc);

    let context = BacktestContext {
        id: format!("ma_crossover_{}", symbol.replace(".", "_")),
        status: backtesting_service::foxhunt::tli::BacktestStatus::Running,
        progress: 0.0,
        current_date: start_time.format("%Y-%m-%d").to_string(),
        trades_executed: 0,
        current_pnl: 0.0,
        started_at: start_time.timestamp_nanos_opt().unwrap_or(0),
        completed_at: Some(end_time.timestamp_nanos_opt().unwrap_or(0)),
        error_message: None,
        strategy_name: "ma_crossover_10_50".to_string(),
        symbols: vec![symbol.to_string()],
        initial_capital,
        parameters: HashMap::new(),
    };

    let trades = engine.execute_backtest(&context).await?;

    // Calculate performance metrics
    let perf_config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&perf_config)?;
    let metrics = analyzer.calculate_metrics(&trades, initial_capital);

    Ok((trades, metrics))
}

/// Helper to print metrics summary
fn print_metrics_summary(
    symbol: &str,
    trades: &[backtesting_service::strategy_engine::BacktestTrade],
    metrics: &PerformanceMetrics,
) {
    println!("\n============================================================");
    println!("  {} - MA Crossover (10/50) Results", symbol);
    println!("============================================================");
    println!("  Total Trades:      {}", trades.len());
    println!("  Total Return:      {:.2}%", metrics.total_return * 100.0);
    println!("  Sharpe Ratio:      {:.3}", metrics.sharpe_ratio);
    println!("  Max Drawdown:      {:.2}%", metrics.max_drawdown * 100.0);
    println!("  Win Rate:          {:.2}%", metrics.win_rate * 100.0);
    println!("  Profit Factor:     {:.3}", metrics.profit_factor);

    if trades.len() > 0 {
        let winning_trades = trades.iter().filter(|t| t.pnl > Decimal::ZERO).count();
        let losing_trades = trades.iter().filter(|t| t.pnl < Decimal::ZERO).count();

        let avg_win = if winning_trades > 0 {
            trades
                .iter()
                .filter(|t| t.pnl > Decimal::ZERO)
                .map(|t| t.pnl.to_f64().unwrap_or(0.0))
                .sum::<f64>()
                / winning_trades as f64
        } else {
            0.0
        };

        let avg_loss = if losing_trades > 0 {
            trades
                .iter()
                .filter(|t| t.pnl < Decimal::ZERO)
                .map(|t| t.pnl.to_f64().unwrap_or(0.0))
                .sum::<f64>()
                / losing_trades as f64
        } else {
            0.0
        };

        println!("  Winning Trades:    {}", winning_trades);
        println!("  Losing Trades:     {}", losing_trades);
        println!("  Avg Win:           ${:.2}", avg_win);
        println!("  Avg Loss:          ${:.2}", avg_loss);
    }
    println!("============================================================\n");
}

// ============================================================================
// INDIVIDUAL SYMBOL TESTS
// ============================================================================

#[tokio::test]
async fn test_ma_crossover_es_fut() -> Result<()> {
    let (trades, metrics) = run_backtest_for_symbol("ES.FUT", 100000.0).await?;

    print_metrics_summary("ES.FUT", &trades, &metrics);

    // Basic validation
    assert!(trades.len() >= 0, "Should execute some trades or none");
    assert!(
        metrics.sharpe_ratio.is_finite(),
        "Sharpe ratio should be finite"
    );

    Ok(())
}

#[tokio::test]
async fn test_ma_crossover_nq_fut() -> Result<()> {
    let (trades, metrics) = run_backtest_for_symbol("NQ.FUT", 100000.0).await?;

    print_metrics_summary("NQ.FUT", &trades, &metrics);

    assert!(trades.len() >= 0, "Should execute some trades or none");
    assert!(
        metrics.sharpe_ratio.is_finite(),
        "Sharpe ratio should be finite"
    );

    Ok(())
}

#[tokio::test]
async fn test_ma_crossover_zn_fut() -> Result<()> {
    let (trades, metrics) = run_backtest_for_symbol("ZN.FUT", 100000.0).await?;

    print_metrics_summary("ZN.FUT", &trades, &metrics);

    assert!(trades.len() >= 0, "Should execute some trades or none");
    assert!(
        metrics.sharpe_ratio.is_finite(),
        "Sharpe ratio should be finite"
    );

    Ok(())
}

#[tokio::test]
async fn test_ma_crossover_6e_fut() -> Result<()> {
    let (trades, metrics) = run_backtest_for_symbol("6E.FUT", 100000.0).await?;

    print_metrics_summary("6E.FUT", &trades, &metrics);

    assert!(trades.len() >= 0, "Should execute some trades or none");
    assert!(
        metrics.sharpe_ratio.is_finite(),
        "Sharpe ratio should be finite"
    );

    Ok(())
}

#[tokio::test]
async fn test_ma_crossover_gc() -> Result<()> {
    let (trades, metrics) = run_backtest_for_symbol("GC", 100000.0).await?;

    print_metrics_summary("GC", &trades, &metrics);

    assert!(trades.len() >= 0, "Should execute some trades or none");
    assert!(
        metrics.sharpe_ratio.is_finite(),
        "Sharpe ratio should be finite"
    );

    Ok(())
}

// ============================================================================
// MULTI-SYMBOL TESTS
// ============================================================================

#[tokio::test]
async fn test_ma_crossover_multi_symbol() -> Result<()> {
    let symbols = vec!["ES.FUT", "NQ.FUT", "ZN.FUT"];
    let initial_capital = 300000.0; // $100k per symbol

    let repositories = create_repositories().await?;
    let config = BacktestingStrategyConfig::default();
    let mut engine = StrategyEngine::new(&config, repositories.clone()).await?;

    let ma_strategy = Box::new(RealMaCrossoverStrategy::new(10, 50));
    engine.register_strategy("ma_crossover_10_50".to_string(), ma_strategy);

    let start_time = DateTime::parse_from_rfc3339("2024-01-02T00:00:00Z")?.with_timezone(&Utc);
    let end_time = DateTime::parse_from_rfc3339("2024-01-03T00:00:00Z")?.with_timezone(&Utc);

    let context = BacktestContext {
        id: "ma_crossover_multi_symbol".to_string(),
        status: backtesting_service::foxhunt::tli::BacktestStatus::Running,
        progress: 0.0,
        current_date: start_time.format("%Y-%m-%d").to_string(),
        trades_executed: 0,
        current_pnl: 0.0,
        started_at: start_time.timestamp_nanos_opt().unwrap_or(0),
        completed_at: Some(end_time.timestamp_nanos_opt().unwrap_or(0)),
        error_message: None,
        strategy_name: "ma_crossover_10_50".to_string(),
        symbols: symbols.iter().map(|s| s.to_string()).collect(),
        initial_capital,
        parameters: HashMap::new(),
    };

    let trades = engine.execute_backtest(&context).await?;

    let perf_config = BacktestingPerformanceConfig::default();
    let analyzer = PerformanceAnalyzer::new(&perf_config)?;
    let metrics = analyzer.calculate_metrics(&trades, initial_capital);

    println!("\n============================================================");
    println!("  MULTI-SYMBOL PORTFOLIO - MA Crossover (10/50)");
    println!("============================================================");
    println!("  Symbols:           {:?}", symbols);
    println!("  Initial Capital:   ${:.2}", initial_capital);
    println!("  Total Trades:      {}", trades.len());
    println!("  Total Return:      {:.2}%", metrics.total_return * 100.0);
    println!("  Sharpe Ratio:      {:.3}", metrics.sharpe_ratio);
    println!("  Max Drawdown:      {:.2}%", metrics.max_drawdown * 100.0);
    println!("  Win Rate:          {:.2}%", metrics.win_rate * 100.0);

    // Trades per symbol
    for symbol in &symbols {
        let symbol_trades = trades.iter().filter(|t| t.symbol == *symbol).count();
        println!("  {} trades:    {}", symbol, symbol_trades);
    }
    println!("============================================================\n");

    assert!(
        trades.len() >= 0,
        "Should execute trades across multiple symbols"
    );

    Ok(())
}

#[tokio::test]
async fn test_ma_crossover_performance_comparison() -> Result<()> {
    println!("\n============================================================");
    println!("  PERFORMANCE COMPARISON ACROSS ASSET CLASSES");
    println!("============================================================\n");

    let symbols = vec![
        ("ES.FUT", "Equity Futures"),
        ("NQ.FUT", "Tech Futures"),
        ("GC", "Gold Commodity"),
        ("ZN.FUT", "Treasury Futures"),
        ("6E.FUT", "FX Futures"),
    ];

    let initial_capital = 100000.0;
    let mut results = Vec::new();

    for (symbol, description) in &symbols {
        match run_backtest_for_symbol(symbol, initial_capital).await {
            Ok((trades, metrics)) => {
                results.push((
                    symbol.to_string(),
                    description.to_string(),
                    trades.len(),
                    metrics,
                ));
            },
            Err(e) => {
                eprintln!("Warning: Failed to backtest {}: {}", symbol, e);
            },
        }
    }

    // Sort by Sharpe ratio
    results.sort_by(|a, b| {
        b.3.sharpe_ratio
            .partial_cmp(&a.3.sharpe_ratio)
            .unwrap_or(std::cmp::Ordering::Equal)
    });

    println!("  Ranking by Sharpe Ratio:");
    println!("  --------------------------------------------------------");
    println!("  Rank  Symbol     Asset Class       Trades  Return%  Sharpe");
    println!("  --------------------------------------------------------");

    for (i, (symbol, desc, trades, metrics)) in results.iter().enumerate() {
        println!(
            "  {:2}    {:8}  {:16}  {:4}    {:6.2}%  {:6.3}",
            i + 1,
            symbol,
            desc,
            trades,
            metrics.total_return * 100.0,
            metrics.sharpe_ratio
        );
    }

    println!("  --------------------------------------------------------\n");

    // Find best and worst performers
    if results.len() > 0 {
        let best = &results[0];
        let worst = &results[results.len() - 1];

        println!(
            "  Best Performer:  {} ({}) - Sharpe: {:.3}",
            best.0, best.1, best.3.sharpe_ratio
        );
        println!(
            "  Worst Performer: {} ({}) - Sharpe: {:.3}",
            worst.0, worst.1, worst.3.sharpe_ratio
        );
        println!("\n============================================================\n");
    }

    assert!(
        results.len() > 0,
        "Should have at least one successful backtest"
    );

    Ok(())
}
