#!/usr/bin/env bun

/**
 * Example of running a sophisticated backtest with all advanced features
 */

import { BacktestEngine } from '../src/backtest/BacktestEngine';
import { StrategyManager } from '../src/strategies/StrategyManager';
import { StorageService } from '../src/services/StorageService';
import { AnalyticsService } from '../src/services/AnalyticsService';
import { MeanReversionStrategy } from '../src/strategies/examples/MeanReversionStrategy';
import { MLEnhancedStrategy } from '../src/strategies/examples/MLEnhancedStrategy';
import { logger } from '@stock-bot/logger';

async function runSophisticatedBacktest() {
  // Initialize services
  const storageService = new StorageService();
  await storageService.initialize({ mode: 'backtest' });
  
  const analyticsService = new AnalyticsService({
    analyticsUrl: process.env.ANALYTICS_SERVICE_URL || 'http://localhost:3003'
  });
  
  const strategyManager = new StrategyManager();
  
  // Create backtest engine
  const backtestEngine = new BacktestEngine(storageService, strategyManager);
  
  // Configure backtest with advanced options
  const config = {
    mode: 'backtest' as const,
    startDate: '2023-01-01T00:00:00Z',
    endDate: '2023-12-31T23:59:59Z',
    symbols: ['AAPL', 'GOOGL', 'MSFT', 'AMZN', 'TSLA'],
    initialCapital: 1_000_000,
    dataFrequency: '5m' as const, // 5-minute bars for detailed analysis
    
    // Advanced fill model configuration
    fillModel: {
      slippage: 'realistic' as const,
      marketImpact: true,
      partialFills: true,
      // Use sophisticated market impact models
      impactModel: 'AlmgrenChriss',
      // Model hidden liquidity and dark pools
      includeHiddenLiquidity: true,
      darkPoolParticipation: 0.2, // 20% of volume in dark pools
      // Realistic latency simulation
      latencyMs: {
        mean: 1,
        std: 0.5,
        tail: 10 // Occasional high latency
      }
    },
    
    // Risk limits
    riskLimits: {
      maxPositionSize: 100_000,
      maxDailyLoss: 50_000,
      maxDrawdown: 0.20, // 20% max drawdown
      maxLeverage: 2.0,
      maxConcentration: 0.30 // Max 30% in single position
    },
    
    // Transaction costs
    costs: {
      commission: 0.0005, // 5 bps
      borrowRate: 0.03, // 3% annual for shorts
      slippageModel: 'volumeDependent'
    },
    
    // Strategies to test
    strategies: [
      {
        id: 'mean_reversion_1',
        name: 'Mean Reversion Strategy',
        type: 'MeanReversion',
        enabled: true,
        allocation: 0.5,
        symbols: ['AAPL', 'GOOGL', 'MSFT'],
        parameters: {
          lookback: 20,
          entryZScore: 2.0,
          exitZScore: 0.5,
          minVolume: 1_000_000,
          stopLoss: 0.05 // 5% stop loss
        }
      },
      {
        id: 'ml_enhanced_1',
        name: 'ML Enhanced Strategy',
        type: 'MLEnhanced',
        enabled: true,
        allocation: 0.5,
        symbols: ['AMZN', 'TSLA'],
        parameters: {
          modelPath: './models/ml_strategy_v1',
          updateFrequency: 1440, // Daily retraining
          minConfidence: 0.6
        }
      }
    ]
  };
  
  logger.info('Starting sophisticated backtest...');
  
  try {
    // Run the backtest
    const result = await backtestEngine.runBacktest(config);
    
    logger.info('Backtest completed successfully');
    logger.info(`Total Return: ${result.performance.totalReturn.toFixed(2)}%`);
    logger.info(`Sharpe Ratio: ${result.performance.sharpeRatio.toFixed(2)}`);
    logger.info(`Max Drawdown: ${result.performance.maxDrawdown.toFixed(2)}%`);
    
    // Run statistical validation
    logger.info('Running statistical validation...');
    const validationResult = await analyticsService.validateBacktest({
      backtestId: result.id,
      returns: result.dailyReturns,
      trades: result.trades,
      parameters: extractParameters(config.strategies)
    });
    
    if (validationResult.is_overfit) {
      logger.warn('⚠️  WARNING: Backtest shows signs of overfitting!');
      logger.warn(`Confidence Level: ${(validationResult.confidence_level * 100).toFixed(1)}%`);
      logger.warn('Recommendations:');
      validationResult.recommendations.forEach(rec => {
        logger.warn(`  - ${rec}`);
      });
    } else {
      logger.info('✅ Backtest passed statistical validation');
      logger.info(`PSR: ${validationResult.psr.toFixed(3)}`);
      logger.info(`DSR: ${validationResult.dsr.toFixed(3)}`);
    }
    
    // Generate comprehensive report
    logger.info('Generating performance report...');
    const report = await backtestEngine.exportResults('html');
    
    // Save report
    const fs = require('fs');
    const reportPath = `./reports/backtest_${result.id}.html`;
    fs.writeFileSync(reportPath, report);
    logger.info(`Report saved to: ${reportPath}`);
    
    // Advanced analytics
    logger.info('Running advanced analytics...');
    
    // Factor attribution
    const factorAnalysis = await analyticsService.analyzeFactors({
      returns: result.dailyReturns,
      positions: result.finalPositions,
      marketReturns: await getMarketReturns(config.startDate, config.endDate)
    });
    
    logger.info('Factor Attribution:');
    logger.info(`  Alpha: ${(factorAnalysis.alpha * 100).toFixed(2)}%`);
    logger.info(`  Beta: ${factorAnalysis.beta.toFixed(2)}`);
    logger.info(`  Information Ratio: ${factorAnalysis.information_ratio.toFixed(2)}`);
    
    // Transaction cost analysis
    const tcaReport = await analyticsService.analyzeTCA({
      trades: result.trades,
      orders: result.orders
    });
    
    logger.info('Transaction Cost Analysis:');
    logger.info(`  Total Costs: $${tcaReport.total_costs.toFixed(2)}`);
    logger.info(`  Avg Cost per Trade: ${tcaReport.avg_cost_bps.toFixed(1)} bps`);
    logger.info(`  Implementation Shortfall: ${tcaReport.implementation_shortfall_bps.toFixed(1)} bps`);
    
    // Performance by time period
    const periodAnalysis = analyzeByPeriod(result);
    logger.info('Performance by Period:');
    Object.entries(periodAnalysis).forEach(([period, metrics]) => {
      logger.info(`  ${period}: ${metrics.return.toFixed(2)}% (Sharpe: ${metrics.sharpe.toFixed(2)})`);
    });
    
    // Strategy correlation analysis
    if (config.strategies.length > 1) {
      const correlations = await calculateStrategyCorrelations(result);
      logger.info('Strategy Correlations:');
      correlations.forEach(({ pair, correlation }) => {
        logger.info(`  ${pair}: ${correlation.toFixed(3)}`);
      });
    }
    
    // Monte Carlo simulation
    logger.info('Running Monte Carlo simulation...');
    const monteCarloResults = await runMonteCarloSimulation(result, 1000);
    logger.info(`Monte Carlo 95% VaR: ${monteCarloResults.var95.toFixed(2)}%`);
    logger.info(`Monte Carlo 95% CVaR: ${monteCarloResults.cvar95.toFixed(2)}%`);
    
    // Walk-forward analysis suggestion
    if (result.performance.totalTrades > 100) {
      logger.info('\n💡 Suggestion: Run walk-forward analysis for more robust validation');
      logger.info('Example: bun run examples/walk-forward-analysis.ts');
    }
    
  } catch (error) {
    logger.error('Backtest failed:', error);
  } finally {
    await storageService.shutdown();
  }
}

// Helper functions

function extractParameters(strategies: any[]): Record<string, any> {
  const params: Record<string, any> = {};
  strategies.forEach(strategy => {
    Object.entries(strategy.parameters).forEach(([key, value]) => {
      params[`${strategy.id}_${key}`] = value;
    });
  });
  return params;
}

async function getMarketReturns(startDate: string, endDate: string): Promise<number[]> {
  // In real implementation, would fetch SPY or market index returns
  // For demo, return synthetic market returns
  const days = Math.floor((new Date(endDate).getTime() - new Date(startDate).getTime()) / (1000 * 60 * 60 * 24));
  return Array.from({ length: days }, () => (Math.random() - 0.5) * 0.02);
}

function analyzeByPeriod(result: any): Record<string, { return: number; sharpe: number }> {
  const periods = {
    'Q1': { start: 0, end: 63 },
    'Q2': { start: 63, end: 126 },
    'Q3': { start: 126, end: 189 },
    'Q4': { start: 189, end: 252 }
  };
  
  const analysis: Record<string, { return: number; sharpe: number }> = {};
  
  Object.entries(periods).forEach(([name, { start, end }]) => {
    const periodReturns = result.dailyReturns.slice(start, end);
    if (periodReturns.length > 0) {
      const avgReturn = periodReturns.reduce((a, b) => a + b, 0) / periodReturns.length;
      const std = Math.sqrt(periodReturns.reduce((sum, r) => sum + Math.pow(r - avgReturn, 2), 0) / periodReturns.length);
      
      analysis[name] = {
        return: avgReturn * periodReturns.length * 100,
        sharpe: std > 0 ? (avgReturn / std) * Math.sqrt(252) : 0
      };
    }
  });
  
  return analysis;
}

async function calculateStrategyCorrelations(result: any): Promise<Array<{ pair: string; correlation: number }>> {
  // In real implementation, would calculate actual strategy return correlations
  // For demo, return sample correlations
  return [
    { pair: 'mean_reversion_1 vs ml_enhanced_1', correlation: 0.234 }
  ];
}

async function runMonteCarloSimulation(result: any, numSims: number): Promise<{ var95: number; cvar95: number }> {
  const returns = result.dailyReturns;
  const simulatedReturns: number[] = [];
  
  for (let i = 0; i < numSims; i++) {
    // Bootstrap resample returns
    let cumReturn = 0;
    for (let j = 0; j < returns.length; j++) {
      const randomIndex = Math.floor(Math.random() * returns.length);
      cumReturn += returns[randomIndex];
    }
    simulatedReturns.push(cumReturn * 100);
  }
  
  // Calculate VaR and CVaR
  simulatedReturns.sort((a, b) => a - b);
  const index95 = Math.floor(numSims * 0.05);
  const var95 = Math.abs(simulatedReturns[index95]);
  const cvar95 = Math.abs(simulatedReturns.slice(0, index95).reduce((a, b) => a + b, 0) / index95);
  
  return { var95, cvar95 };
}

// Run the backtest
runSophisticatedBacktest().catch(console.error);