import { EventEmitter } from 'events';
import { IServiceContainer } from '@stock-bot/di';
import { PerformanceAnalyzer } from '../analytics/PerformanceAnalyzer';
import { DataManager } from '../data/DataManager';
import { StorageService } from '../services/StorageService';
import { StrategyManager } from '../strategies/StrategyManager';
import { BacktestConfigSchema, MarketData, MarketMicrostructure, PerformanceMetrics } from '../types';
import { MarketSimulator } from './MarketSimulator';

interface BacktestEvent {
  timestamp: number;
  type: 'market_data' | 'strategy_signal' | 'order_fill';
  data: any;
}

interface BacktestResult {
  // Identification
  backtestId: string;
  status: 'completed' | 'failed' | 'cancelled';
  completedAt: string;
  
  // Configuration
  config: {
    name: string;
    strategy: string;
    symbols: string[];
    startDate: string;
    endDate: string;
    initialCapital: number;
    commission: number;
    slippage: number;
    dataFrequency: string;
  };
  
  // Performance metrics
  metrics: {
    totalReturn: number;
    sharpeRatio: number;
    maxDrawdown: number;
    winRate: number;
    totalTrades: number;
    profitFactor: number;
    profitableTrades: number;
    avgWin: number;
    avgLoss: number;
    expectancy: number;
    calmarRatio: number;
    sortinoRatio: number;
  };
  
  // Chart data
  equity: Array<{ date: string; value: number }>;
  ohlcData: Record<string, any[]>;
  
  // Trade history
  trades: Array<{
    id: string;
    symbol: string;
    entryDate: string;
    exitDate: string | null;
    entryPrice: number;
    exitPrice: number;
    quantity: number;
    side: string;
    pnl: number;
    pnlPercent: number;
    commission: number;
    duration: number;
  }>;
  
  // Positions
  positions: Array<{
    symbol: string;
    quantity: number;
    averagePrice: number;
    currentPrice: number;
    unrealizedPnl: number;
    realizedPnl: number;
  }>;
  
  // Analytics
  analytics: {
    drawdownSeries: { timestamp: number; value: number }[];
    dailyReturns: number[];
    monthlyReturns: Record<string, number>;
    exposureTime: number;
    riskMetrics: Record<string, number>;
  };
}

export class BacktestEngine extends EventEmitter {
  private eventQueue: BacktestEvent[] = [];
  private currentTime: number = 0;
  private equityCurve: { timestamp: number; value: number }[] = [];
  private isRunning = false;
  private isPaused = false;
  private speedMultiplier: number | null = 1; // null means unlimited speed
  private lastProcessTime = 0;
  private dataManager: DataManager;
  private marketSimulator: MarketSimulator;
  private performanceAnalyzer: PerformanceAnalyzer;
  private microstructures: Map<string, MarketMicrostructure> = new Map();
  private container: IServiceContainer;
  private runId: string | null = null;
  private progressUpdateInterval = 100; // Update progress every 100 events
  private totalEvents = 0;
  private initialCapital: number = 100000;
  private commission: number = 0.001; // Default 0.1%
  private slippage: number = 0.0001; // Default 0.01%
  private pendingOrders: Map<string, any> = new Map();
  private ordersListenerSetup = false;

  constructor(
    container: IServiceContainer,
    private storageService: StorageService,
    private strategyManager: StrategyManager
  ) {
    super();
    this.container = container;
    this.dataManager = new DataManager(storageService);
    this.marketSimulator = new MarketSimulator({
      useHistoricalSpreads: true,
      modelHiddenLiquidity: true,
      includeDarkPools: true,
      latencyMs: 1
    });
    // Don't create performance analyzer here - wait for runBacktest
    // this.performanceAnalyzer = new PerformanceAnalyzer(this.initialCapital);
    
    // Set up order listener immediately
    this.setupOrderListener();
  }

  async runBacktest(config: any): Promise<BacktestResult> {
    // Validate config
    const validatedConfig = BacktestConfigSchema.parse(config);
    
    this.container.logger.info(`Starting backtest from ${validatedConfig.startDate} to ${validatedConfig.endDate}`);
    
    // Reset state
    this.reset();
    this.isRunning = true;
    this.initialCapital = validatedConfig.initialCapital;
    this.commission = validatedConfig.commission ?? 0.001;
    this.slippage = validatedConfig.slippage ?? 0.0001;
    
    // Recreate performance analyzer with correct initial capital
    this.performanceAnalyzer = new PerformanceAnalyzer(this.initialCapital);
    
    // Initialize equity curve with starting capital
    this.equityCurve.push({
      timestamp: new Date(validatedConfig.startDate).getTime(),
      value: this.initialCapital
    });
    
    // Initialize performance analyzer with starting capital
    this.performanceAnalyzer.addEquityPoint(
      new Date(validatedConfig.startDate),
      this.initialCapital
    );
    
    this.container.logger.info(`[BacktestEngine] Initial capital set to ${this.initialCapital}, equity curve initialized with ${this.equityCurve.length} points`);
    
    // Generate backtest ID and store runId if provided
    const backtestId = `backtest_${Date.now()}`;
    this.runId = config.runId || null;
    
    // Set speed multiplier from config
    if (validatedConfig.speed) {
      switch (validatedConfig.speed) {
        case 'max':
          this.speedMultiplier = null; // Unlimited speed
          break;
        case 'realtime':
          this.speedMultiplier = 1;
          break;
        case '2x':
          this.speedMultiplier = 2;
          break;
        case '5x':
          this.speedMultiplier = 5;
          break;
        case '10x':
          this.speedMultiplier = 10;
          break;
        default:
          this.speedMultiplier = null; // Default to max speed
      }
      this.container.logger.info(`[BacktestEngine] Speed set to: ${validatedConfig.speed} (multiplier: ${this.speedMultiplier})`);
    }
    
    try {
      // Load historical data with multi-resolution support
      const dataMap = await this.dataManager.loadHistoricalData(
        validatedConfig.symbols,
        new Date(validatedConfig.startDate),
        new Date(validatedConfig.endDate),
        validatedConfig.dataFrequency,
        true // Include extended hours
      );
      
      // Load market microstructure for each symbol
      await this.loadMarketMicrostructure(validatedConfig.symbols);
      
      // Convert to flat array and sort by time
      const marketData: MarketData[] = [];
      dataMap.forEach((data, symbol) => {
        marketData.push(...data);
      });
      marketData.sort((a, b) => a.data.timestamp - b.data.timestamp);
      
      this.container.logger.info(`Loaded ${marketData.length} market data points`);
      
      // Initialize strategies
      const strategies = validatedConfig.strategies || [{
        id: `${validatedConfig.strategy}-${Date.now()}`,
        name: validatedConfig.strategy,
        enabled: true,
        parameters: {
          symbols: validatedConfig.symbols,
          initialCapital: validatedConfig.initialCapital,
          // Add any default strategy parameters here
        },
        symbols: validatedConfig.symbols,
        allocation: 1.0 // Use 100% of capital
      }];
      
      await this.strategyManager.initializeStrategies(strategies);
      this.container.logger.info(`Initialized ${strategies.length} strategies`);
      
      // Don't setup strategy order listeners - we already listen to StrategyManager
      // this.setupStrategyOrderListeners();
      
      // Convert market data to events
      this.populateEventQueue(marketData);
      
      // Main backtest loop
      await this.processEvents();
      
      // Get trade history from Rust core
      const tradingEngine = this.strategyManager.getTradingEngine();
      let closedTrades: any[] = [];
      let tradeCount = 0;
      if (tradingEngine) {
        if (tradingEngine.getClosedTrades) {
          try {
            const tradesJson = tradingEngine.getClosedTrades();
            closedTrades = JSON.parse(tradesJson);
            this.container.logger.info(`Retrieved ${closedTrades.length} closed trades from Rust core`);
          } catch (error) {
            this.container.logger.warn('Failed to get closed trades from Rust core:', error);
          }
        }
        if (tradingEngine.getTradeCount) {
          try {
            tradeCount = tradingEngine.getTradeCount();
            this.container.logger.info(`Total trades executed: ${tradeCount}`);
          } catch (error) {
            this.container.logger.warn('Failed to get trade count from Rust core:', error);
          }
        }
      }
      
      // Calculate final metrics
      const performance = this.calculatePerformance(closedTrades);
      
      // Get final positions
      const finalPositions = await this.getFinalPositions();
      
      // Create comprehensive frontend-ready result
      const result: BacktestResult = {
        // Identification
        backtestId,
        status: 'completed' as const,
        completedAt: new Date().toISOString(),
        
        // Configuration used
        config: {
          name: validatedConfig.name || 'Backtest',
          strategy: validatedConfig.strategy,
          symbols: validatedConfig.symbols,
          startDate: validatedConfig.startDate,
          endDate: validatedConfig.endDate,
          initialCapital: validatedConfig.initialCapital,
          commission: validatedConfig.commission || 0,
          slippage: validatedConfig.slippage || 0,
          dataFrequency: validatedConfig.dataFrequency || '1d'
        },
        
        // Performance metrics (frontend-ready)
        metrics: {
          totalReturn: performance.totalReturn,
          sharpeRatio: performance.sharpeRatio,
          maxDrawdown: performance.maxDrawdown,
          winRate: performance.winRate,
          totalTrades: tradeCount || performance.totalTrades,
          profitFactor: performance.profitFactor || 0,
          profitableTrades: Math.round(performance.totalTrades * performance.winRate / 100),
          avgWin: performance.avgWin || 0,
          avgLoss: performance.avgLoss || 0,
          expectancy: performance.expectancy || 0,
          calmarRatio: performance.calmarRatio || 0,
          sortinoRatio: performance.sortinoRatio || 0
        },
        
        // Chart data (frontend-ready format)
        equity: this.equityCurve
          .sort((a, b) => a.timestamp - b.timestamp)
          .map(point => ({
            date: new Date(point.timestamp).toISOString(),
            value: point.value
          })),
        
        // OHLC data for charts
        ohlcData: this.getOHLCData(marketData, validatedConfig.symbols),
        
        // Trade history (frontend-ready)
        trades: closedTrades.map(trade => ({
          id: trade.id,
          symbol: trade.symbol,
          entryDate: trade.entry_time,
          exitDate: trade.exit_time,
          entryPrice: trade.entry_price,
          exitPrice: trade.exit_price,
          quantity: trade.quantity,
          side: trade.side === 'Buy' ? 'buy' : 'sell',
          pnl: trade.pnl,
          pnlPercent: trade.pnl_percent,
          commission: trade.commission,
          duration: trade.duration_ms
        })),
        
        // Final positions
        positions: finalPositions.map(pos => ({
          symbol: pos.symbol,
          quantity: pos.quantity,
          averagePrice: pos.avgPrice,
          currentPrice: pos.currentPrice || pos.avgPrice,
          unrealizedPnl: pos.unrealizedPnl || 0,
          realizedPnl: pos.realizedPnl || 0
        })),
        
        // Additional analytics
        analytics: {
          drawdownSeries: this.calculateDrawdown(),
          dailyReturns: this.calculateDailyReturns(),
          monthlyReturns: this.calculateMonthlyReturns(),
          exposureTime: this.calculateExposureTime(closedTrades),
          riskMetrics: this.calculateRiskMetrics(closedTrades)
        }
      };
      
      await this.storeResults(result);
      
      this.container.logger.info(`Backtest completed: ${performance.totalTrades} trades, ${performance.totalReturn}% return`);
      
      return result;
      
    } catch (error) {
      this.container.logger.error('Backtest failed:', error);
      throw error;
    } finally {
      this.isRunning = false;
      this.reset();
    }
  }

  private async loadHistoricalData(config: any): Promise<MarketData[]> {
    const data: MarketData[] = [];
    const startDate = new Date(config.startDate);
    const endDate = new Date(config.endDate);
    
    try {
      for (const symbol of config.symbols) {
        const bars = await this.storageService.getHistoricalBars(
          symbol,
          startDate,
          endDate,
          config.dataFrequency
        );
        
        // If no data found, use mock data
        if (!bars || bars.length === 0) {
          this.container.logger.warn(`No historical data found for ${symbol}, using mock data`);
          
          // Tell the Rust core to generate mock data
          const tradingEngine = this.strategyManager.getTradingEngine();
          if (tradingEngine && tradingEngine.generateMockData) {
            await tradingEngine.generateMockData(
              symbol,
              startDate.getTime(),
              endDate.getTime(),
              42 // seed for reproducibility
            );
            
            // For now, we'll generate mock data on the TypeScript side
            // as the Rust integration needs more work
            const mockData = this.generateMockData(symbol, startDate, endDate);
            data.push(...mockData);
          } else {
            // Fallback to TypeScript mock data generation
            const mockData = this.generateMockData(symbol, startDate, endDate);
            data.push(...mockData);
          }
        } else {
          // Convert to MarketData format
          bars.forEach(bar => {
            data.push({
              type: 'bar',
              data: {
                symbol,
                open: bar.open,
                high: bar.high,
                low: bar.low,
                close: bar.close,
                volume: bar.volume,
                vwap: bar.vwap,
                timestamp: new Date(bar.timestamp).getTime()
              }
            });
          });
        }
      }
    } catch (error) {
      this.container.logger.warn('Error loading historical data, using mock data:', error);
      
      // Generate mock data for all symbols
      for (const symbol of config.symbols) {
        const mockData = this.generateMockData(symbol, startDate, endDate);
        data.push(...mockData);
      }
    }
    
    // Sort by timestamp
    data.sort((a, b) => {
      const timeA = a.data.timestamp;
      const timeB = b.data.timestamp;
      return timeA - timeB;
    });
    
    return data;
  }
  
  private generateMockData(symbol: string, startDate: Date, endDate: Date): MarketData[] {
    const data: MarketData[] = [];
    const startTime = startDate.getTime();
    const endTime = endDate.getTime();
    const interval = 24 * 60 * 60 * 1000; // 1 day in milliseconds
    
    let price = 100; // Base price
    let currentTime = startTime;
    let trend = 0; // Current trend direction
    let trendStrength = 0;
    let trendDuration = 0;
    
    while (currentTime <= endTime) {
      // Every 10-30 days, change trend (more frequent for testing)
      if (trendDuration <= 0) {
        trend = Math.random() > 0.5 ? 1 : -1;
        trendStrength = 0.003 + Math.random() * 0.005; // 0.3% to 0.8% daily trend
        trendDuration = Math.floor(10 + Math.random() * 20); // Shorter trends
      }
      
      // Generate price movement with trend and noise
      const trendComponent = trend * trendStrength;
      const noiseComponent = (Math.random() - 0.5) * 0.03; // +/- 1.5% noise
      const changePercent = trendComponent + noiseComponent;
      price = price * (1 + changePercent);
      
      // Generate OHLC with realistic intraday movement
      const open = price * (1 + (Math.random() - 0.5) * 0.005);
      const dayRange = 0.01 + Math.random() * 0.02; // 1-3% daily range
      const high = Math.max(open, price) * (1 + Math.random() * dayRange);
      const low = Math.min(open, price) * (1 - Math.random() * dayRange);
      const close = low + Math.random() * (high - low);
      const volume = Math.random() * 1000000 + 500000;
      
      trendDuration--;
      
      data.push({
        type: 'bar',
        data: {
          symbol,
          open,
          high,
          low,
          close,
          volume,
          vwap: (open + high + low + close) / 4,
          timestamp: currentTime
        }
      });
      
      currentTime += interval;
      price = close; // Next bar opens at previous close
    }
    
    return data;
  }

  private populateEventQueue(marketData: MarketData[]): void {
    // Convert market data to events
    marketData.forEach(data => {
      this.eventQueue.push({
        timestamp: data.data.timestamp,
        type: 'market_data',
        data
      });
    });
    
    // Sort by timestamp (should already be sorted)
    this.eventQueue.sort((a, b) => a.timestamp - b.timestamp);
  }

  private async processEvents(): Promise<void> {
    const tradingEngine = this.strategyManager.getTradingEngine();
    let lastEquityUpdate = 0;
    const equityUpdateInterval = 60000; // Update equity every minute
    
    this.totalEvents = this.eventQueue.length;
    this.container.logger.info(`[BacktestEngine] Processing ${this.totalEvents} events with speed multiplier: ${this.speedMultiplier}`);
    
    let processedCount = 0;
    
    while (this.eventQueue.length > 0 && this.isRunning) {
      // Check if paused
      if (this.isPaused) {
        await new Promise(resolve => setTimeout(resolve, 100));
        continue;
      }
      
      const event = this.eventQueue.shift()!;
      processedCount++;
      
      // Apply speed control if not unlimited
      if (this.speedMultiplier !== null && this.speedMultiplier > 0) {
        // Base delay in milliseconds for processing each event
        // For 1x speed: 1000ms per event (1 event per second)
        // For 2x speed: 500ms per event (2 events per second)
        // For 10x speed: 100ms per event (10 events per second)
        const baseDelay = 1000; // milliseconds
        const actualDelay = baseDelay / this.speedMultiplier;
        
        // Add the delay
        if (actualDelay > 1) {
          if (processedCount % 50 === 0) { // Log every 50 events to avoid spam
            this.container.logger.debug(`[BacktestEngine] Applying delay: ${actualDelay}ms (speed: ${this.speedMultiplier}x)`);
          }
          await new Promise(resolve => setTimeout(resolve, actualDelay));
        }
        
        // Also send progress updates more frequently at slower speeds
        if (processedCount % Math.max(1, Math.floor(10 / this.speedMultiplier)) === 0) {
          const progress = Math.round((processedCount / this.totalEvents) * 100);
          this.sendProgressUpdate(progress, new Date(event.timestamp).toISOString());
        }
      }
      
      this.lastProcessTime = Date.now();
      
      // Advance time
      this.currentTime = event.timestamp;
      if (tradingEngine) {
        await tradingEngine.advanceTime(this.currentTime);
      }
      
      // Process event based on type
      switch (event.type) {
        case 'market_data':
          await this.processMarketData(event.data);
          break;
          
        case 'strategy_signal':
          await this.processStrategySignal(event.data);
          break;
          
        case 'order_fill':
          await this.processFill(event.data);
          break;
      }
      
      // Update equity curve periodically
      if (this.currentTime - lastEquityUpdate > equityUpdateInterval) {
        await this.updateEquityCurve();
        lastEquityUpdate = this.currentTime;
      }
      
      // Send progress update via WebSocket (unless already sent in speed control)
      if (this.speedMultiplier === null && processedCount % this.progressUpdateInterval === 0) {
        const progress = Math.round((processedCount / this.totalEvents) * 100);
        this.sendProgressUpdate(progress, new Date(this.currentTime).toISOString());
        
        // Also emit local progress event
        this.emit('progress', {
          processed: processedCount,
          total: this.totalEvents,
          remaining: this.eventQueue.length,
          currentTime: new Date(this.currentTime),
          progress
        });
      }
    }
    
    // Final equity update
    await this.updateEquityCurve();
    
    // Send 100% progress
    this.sendProgressUpdate(100, new Date(this.currentTime).toISOString());
  }

  private async processMarketData(data: MarketData): Promise<void> {
    this.container.logger.info(`[BacktestEngine] processMarketData called for ${data.data.symbol} @ ${data.data.close}`);
    const tradingEngine = this.strategyManager.getTradingEngine();
    if (!tradingEngine) {
      this.container.logger.warn(`[BacktestEngine] No trading engine available`);
      return;
    }
    
    // Process through market simulator for realistic orderbook
    const orderbook = this.marketSimulator.processMarketData(data);
    
    if (orderbook) {
      // Update trading engine with simulated orderbook
      if (orderbook.bids.length > 0 && orderbook.asks.length > 0) {
        tradingEngine.updateQuote(
          orderbook.symbol,
          orderbook.bids[0].price,
          orderbook.asks[0].price,
          orderbook.bids[0].size,
          orderbook.asks[0].size
        );
      }
      
      // Set microstructure in trading core for realistic fills
      const microstructure = this.microstructures.get(orderbook.symbol);
      if (microstructure && tradingEngine.setMicrostructure) {
        tradingEngine.setMicrostructure(orderbook.symbol, microstructure);
      }
    } else {
      // Fallback to simple processing
      switch (data.type) {
        case 'quote':
          tradingEngine.updateQuote(
            data.data.symbol,
            data.data.bid,
            data.data.ask,
            data.data.bidSize,
            data.data.askSize
          );
          break;
          
        case 'trade':
          tradingEngine.updateTrade(
            data.data.symbol,
            data.data.price,
            data.data.size,
            data.data.side
          );
          break;
          
        case 'bar':
          const spread = data.data.high - data.data.low;
          const spreadBps = (spread / data.data.close) * 10000;
          const halfSpread = data.data.close * Math.min(spreadBps, 10) / 20000;
          
          tradingEngine.updateQuote(
            data.data.symbol,
            data.data.close - halfSpread,
            data.data.close + halfSpread,
            data.data.volume / 100,
            data.data.volume / 100
          );
          break;
      }
    }
    
    // Let strategies process the data
    this.container.logger.info(`[BacktestEngine] Forwarding data to strategy manager for ${data.data.symbol}`);
    await this.strategyManager.onMarketData(data);
    
    // Check for any pending orders that should be filled
    await this.checkAndFillOrders(data);
    
    // Track performance
    this.performanceAnalyzer.addEquityPoint(
      new Date(this.currentTime),
      await this.getPortfolioValue()
    );
  }

  private async processStrategySignal(signal: any): Promise<void> {
    // Strategy signals are handled by strategy manager
    // This is here for future extensions
  }

  private async processFill(fill: any): Promise<void> {
    this.container.logger.info(`[BacktestEngine] Processing fill: ${fill.side} ${fill.quantity} ${fill.symbol} @ ${fill.price} with timestamp ${fill.timestamp}`);
    
    // Process fill in trading engine for position tracking
    const tradingEngine = this.strategyManager.getTradingEngine();
    if (tradingEngine) {
      this.container.logger.info(`[BacktestEngine] Trading engine available, processing fill`);
      this.container.logger.info(`[BacktestEngine] Current time in trading engine before advance: ${tradingEngine.getCurrentTime()}`);
      
      // Make sure time is properly advanced
      if (fill.timestamp) {
        await tradingEngine.advanceTime(fill.timestamp);
        this.container.logger.info(`[BacktestEngine] Advanced trading engine time to ${fill.timestamp}, current time now: ${tradingEngine.getCurrentTime()}`);
      }
      
      // Use the new process_fill_with_metadata method if available
      if (tradingEngine.processFillWithMetadata) {
        const fillResult = await tradingEngine.processFillWithMetadata(
          fill.symbol,
          fill.price,
          fill.quantity,
          fill.side,
          fill.commission || 0,
          fill.orderId || null,
          fill.strategyId || null
        );
        this.container.logger.debug('Fill processed with tracking:', fillResult);
      } else {
        // Fallback to old method
        const fillResult = await tradingEngine.processFill(
          fill.symbol,
          fill.price,
          fill.quantity,
          fill.side,
          fill.commission || 0
        );
        this.container.logger.debug('Fill processed:', fillResult);
      }
    } else {
      this.container.logger.warn(`[BacktestEngine] No trading engine available to process fill!`);
    }
    
    // Notify strategies of fill
    const strategy = fill.strategyId ? this.strategyManager.getStrategy(fill.strategyId) : null;
    if (strategy) {
      await strategy.onOrderUpdate({
        orderId: fill.orderId,
        symbol: fill.symbol,
        side: fill.side,
        status: 'filled',
        fills: [fill]
      });
    }
    
    // Store in database
    await this.storageService.storeFill(fill);
  }

  private async updateEquityCurve(): Promise<void> {
    const totalEquity = await this.getPortfolioValue();
    
    this.container.logger.debug(`[updateEquityCurve] currentTime=${this.currentTime}, totalEquity=${totalEquity}, initialCapital=${this.initialCapital}`);
    
    // Don't add duplicate points at the same timestamp
    const lastPoint = this.equityCurve[this.equityCurve.length - 1];
    if (lastPoint && lastPoint.timestamp === this.currentTime) {
      // Update the value instead of adding a duplicate
      this.container.logger.debug(`[updateEquityCurve] Updating existing point at ${this.currentTime}: ${lastPoint.value} -> ${totalEquity}`);
      lastPoint.value = totalEquity;
    } else {
      this.container.logger.debug(`[updateEquityCurve] Adding new point at ${this.currentTime}: ${totalEquity}`);
      this.equityCurve.push({
        timestamp: this.currentTime,
        value: totalEquity
      });
    }
  }
  
  private async getPortfolioValue(): Promise<number> {
    const tradingEngine = this.strategyManager.getTradingEngine();
    if (!tradingEngine) {
      this.container.logger.debug(`[getPortfolioValue] No trading engine, returning initialCapital: ${this.initialCapital}`);
      return this.initialCapital;
    }
    
    try {
      // Get current P&L
      const [realized, unrealized] = tradingEngine.getTotalPnl();
      const totalValue = this.initialCapital + realized + unrealized;
      
      this.container.logger.debug(`[getPortfolioValue] P&L: realized=${realized}, unrealized=${unrealized}, initialCapital=${this.initialCapital}, totalValue=${totalValue}`);
      
      // Ensure we never return 0 or negative values that would cause spikes
      // This handles the case where getTotalPnl might not be initialized yet
      if (totalValue <= 0 || isNaN(totalValue)) {
        this.container.logger.debug(`[getPortfolioValue] Invalid totalValue, returning initialCapital: ${this.initialCapital}`);
        return this.initialCapital;
      }
      
      return totalValue;
    } catch (error) {
      // If getTotalPnl fails, return initial capital
      this.container.logger.warn('Failed to get total P&L, using initial capital:', error);
      return this.initialCapital;
    }
  }

  private calculatePerformance(closedTrades: any[] = []): PerformanceMetrics {
    // Use sophisticated performance analyzer
    // Add closed trades from Rust core
    closedTrades.forEach(trade => {
      this.performanceAnalyzer.addTrade({
        entryTime: new Date(trade.entry_time),
        exitTime: new Date(trade.exit_time),
        symbol: trade.symbol,
        side: trade.side === 'Buy' ? 'long' : 'short',
        entryPrice: trade.entry_price,
        exitPrice: trade.exit_price,
        quantity: trade.quantity,
        commission: trade.commission || 0,
        pnl: trade.pnl || 0,
        returnPct: trade.pnl_percent || 0,
        holdingPeriod: trade.duration_ms / 60000, // Convert to minutes
        mae: 0, // Not tracked yet
        mfe: 0  // Not tracked yet
      });
    });
    
    const metrics = this.performanceAnalyzer.analyze();
    
    // Add drawdown analysis
    const drawdownAnalysis = this.performanceAnalyzer.analyzeDrawdowns();
    
    return {
      ...metrics,
      maxDrawdown: drawdownAnalysis.maxDrawdown,
      maxDrawdownDuration: drawdownAnalysis.maxDrawdownDuration
    };
  }

  private sendProgressUpdate(progress: number, currentDate: string): void {
    if (!this.runId) return;
    
    try {
      // Try to send WebSocket update to web-api
      const url = `http://localhost:2003/api/runs/${this.runId}/progress`;
      fetch(url, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ progress, currentDate })
      }).catch(err => {
        // Ignore errors - WebSocket updates are best-effort
        this.container.logger.debug('Failed to send progress update:', err);
      });
    } catch (error) {
      // Ignore errors
    }
  }
  
  private calculateDrawdown(): { timestamp: number; value: number }[] {
    const drawdowns: { timestamp: number; value: number }[] = [];
    let peak = this.equityCurve[0]?.value || 0;
    
    for (const point of this.equityCurve) {
      if (point.value > peak) {
        peak = point.value;
      }
      const drawdown = ((point.value - peak) / peak) * 100;
      drawdowns.push({
        timestamp: point.timestamp,
        value: drawdown
      });
    }
    
    return drawdowns;
  }

  private calculateMonthlyReturns(): Record<string, number> {
    const monthlyReturns: Record<string, number> = {};
    const monthlyEquity = new Map<string, { start: number; end: number }>();
    
    for (const point of this.equityCurve) {
      const date = new Date(point.timestamp);
      const monthKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;
      
      if (!monthlyEquity.has(monthKey)) {
        monthlyEquity.set(monthKey, { start: point.value, end: point.value });
      } else {
        const month = monthlyEquity.get(monthKey)!;
        month.end = point.value;
      }
    }
    
    for (const [month, values] of monthlyEquity) {
      monthlyReturns[month] = ((values.end - values.start) / values.start) * 100;
    }
    
    return monthlyReturns;
  }
  
  private calculateExposureTime(closedTrades: any[] = []): number {
    if (closedTrades.length === 0) return 0;
    
    let totalExposureTime = 0;
    for (const trade of closedTrades) {
      totalExposureTime += trade.duration_ms || 0;
    }
    
    // Use equity curve to determine actual trading period
    const startTime = this.equityCurve.length > 0 ? this.equityCurve[0].timestamp : 0;
    const endTime = this.equityCurve.length > 0 ? this.equityCurve[this.equityCurve.length - 1].timestamp : 0;
    const totalTime = endTime - startTime;
    
    return totalTime > 0 ? (totalExposureTime / totalTime) * 100 : 0;
  }
  
  private calculateRiskMetrics(closedTrades: any[] = []): Record<string, number> {
    const returns = this.calculateDailyReturns();
    
    // Calculate various risk metrics
    const avgReturn = returns.reduce((a, b) => a + b, 0) / returns.length;
    const variance = returns.reduce((sum, r) => sum + Math.pow(r - avgReturn, 2), 0) / returns.length;
    const stdDev = Math.sqrt(variance);
    
    // Downside deviation (for Sortino)
    const downsideReturns = returns.filter(r => r < 0);
    const downsideVariance = downsideReturns.reduce((sum, r) => sum + Math.pow(r, 2), 0) / downsideReturns.length;
    const downsideDeviation = Math.sqrt(downsideVariance);
    
    return {
      volatility: stdDev * Math.sqrt(252), // Annualized
      downsideDeviation: downsideDeviation * Math.sqrt(252),
      var95: this.calculateVaR(returns, 0.95),
      var99: this.calculateVaR(returns, 0.99),
      cvar95: this.calculateCVaR(returns, 0.95),
      maxConsecutiveLosses: this.calculateMaxConsecutiveLosses(closedTrades)
    };
  }
  
  private calculateVaR(returns: number[], confidence: number): number {
    const sorted = [...returns].sort((a, b) => a - b);
    const index = Math.floor((1 - confidence) * sorted.length);
    return sorted[index] || 0;
  }
  
  private calculateCVaR(returns: number[], confidence: number): number {
    const sorted = [...returns].sort((a, b) => a - b);
    const index = Math.floor((1 - confidence) * sorted.length);
    const tail = sorted.slice(0, index + 1);
    return tail.reduce((a, b) => a + b, 0) / tail.length;
  }
  
  private calculateMaxConsecutiveLosses(closedTrades: any[] = []): number {
    let maxLosses = 0;
    let currentLosses = 0;
    
    for (const trade of closedTrades) {
      if (trade.pnl && trade.pnl < 0) {
        currentLosses++;
        maxLosses = Math.max(maxLosses, currentLosses);
      } else {
        currentLosses = 0;
      }
    }
    
    return maxLosses;
  }

  private calculateDailyReturns(): number[] {
    const dailyReturns: number[] = [];
    const dailyEquity = new Map<string, number>();
    
    // Group equity by day
    for (const point of this.equityCurve) {
      const date = new Date(point.timestamp).toDateString();
      dailyEquity.set(date, point.value);
    }
    
    // Calculate returns
    const dates = Array.from(dailyEquity.keys()).sort();
    for (let i = 1; i < dates.length; i++) {
      const prevValue = dailyEquity.get(dates[i - 1])!;
      const currValue = dailyEquity.get(dates[i])!;
      const dailyReturn = ((currValue - prevValue) / prevValue) * 100;
      dailyReturns.push(dailyReturn);
    }
    
    return dailyReturns;
  }

  private async getFinalPositions(): Promise<any[]> {
    const tradingEngine = this.strategyManager.getTradingEngine();
    if (!tradingEngine) {return [];}
    
    const positions = JSON.parse(tradingEngine.getOpenPositions());
    return positions;
  }

  private async storeResults(result: BacktestResult): Promise<void> {
    // Store performance metrics
    await this.storageService.storeStrategyPerformance(
      result.id,
      result.performance
    );
    
    // Could also store detailed results in a separate table or file
    this.container.logger.debug(`Backtest results stored with ID: ${result.id}`);
  }

  private reset(): void {
    this.eventQueue = [];
    this.currentTime = 0;
    this.equityCurve = [];
    this.pendingOrders.clear();
    this.ordersListenerSetup = false;
    this.isPaused = false;
    this.speedMultiplier = 1;
    this.lastProcessTime = 0;
    this.marketSimulator.reset();
  }
  
  private async loadMarketMicrostructure(symbols: string[]): Promise<void> {
    // In real implementation, would load from database
    // For now, create reasonable defaults based on symbol characteristics
    for (const symbol of symbols) {
      const microstructure: MarketMicrostructure = {
        symbol,
        avgSpreadBps: 2 + Math.random() * 3, // 2-5 bps
        dailyVolume: 10_000_000 * (1 + Math.random() * 9), // 10-100M shares
        avgTradeSize: 100 + Math.random() * 400, // 100-500 shares
        volatility: 0.15 + Math.random() * 0.25, // 15-40% annual vol
        tickSize: 0.01,
        lotSize: 1,
        intradayVolumeProfile: this.generateIntradayProfile()
      };
      
      this.microstructures.set(symbol, microstructure);
      this.marketSimulator.setMicrostructure(symbol, microstructure);
    }
  }
  
  private generateIntradayProfile(): number[] {
    // U-shaped intraday volume pattern
    const profile = new Array(24).fill(0);
    const tradingHours = [9, 10, 11, 12, 13, 14, 15, 16]; // 9:30 AM to 4:00 PM
    
    tradingHours.forEach((hour, idx) => {
      if (idx === 0 || idx === tradingHours.length - 1) {
        // High volume at open and close
        profile[hour] = 0.2;
      } else if (idx === 1 || idx === tradingHours.length - 2) {
        // Moderate volume
        profile[hour] = 0.15;
      } else {
        // Lower midday volume
        profile[hour] = 0.1;
      }
    });
    
    // Normalize
    const sum = profile.reduce((a, b) => a + b, 0);
    return profile.map(v => v / sum);
  }
  

  async stopBacktest(): Promise<void> {
    this.isRunning = false;
    this.container.logger.info('Backtest stop requested');
  }
  
  async exportResults(format: 'json' | 'csv' | 'html' = 'json'): Promise<string> {
    // Get trades from Rust core
    const tradingEngine = this.strategyManager.getTradingEngine();
    let closedTrades: any[] = [];
    if (tradingEngine && tradingEngine.getClosedTrades) {
      try {
        const tradesJson = tradingEngine.getClosedTrades();
        closedTrades = JSON.parse(tradesJson);
      } catch (error) {
        this.container.logger.warn('Failed to get closed trades for export:', error);
      }
    }
    
    const result = {
      summary: this.calculatePerformance(closedTrades),
      trades: closedTrades,
      equityCurve: this.equityCurve,
      drawdowns: this.calculateDrawdown(),
      dataQuality: this.dataManager.getDataQualityReport(),
      performanceReport: this.performanceAnalyzer.exportReport()
    };
    
    switch (format) {
      case 'json':
        return JSON.stringify(result, null, 2);
      case 'csv':
        // Convert to CSV format
        return this.convertToCSV(result);
      case 'html':
        // Generate HTML report
        return this.generateHTMLReport(result);
      default:
        return JSON.stringify(result);
    }
  }
  
  private convertToCSV(result: any): string {
    // Simple CSV conversion for trades
    const headers = ['Date', 'Symbol', 'Side', 'Entry', 'Exit', 'Quantity', 'PnL', 'Return%'];
    const rows = result.trades.map(t => [
      new Date(t.entry_time).toISOString(),
      t.symbol,
      t.side === 'Buy' ? 'buy' : 'sell',
      t.entry_price,
      t.exit_price,
      t.quantity,
      t.pnl,
      t.pnl_percent
    ]);
    
    return [headers, ...rows].map(row => row.join(',')).join('\n');
  }
  
  private generateHTMLReport(result: any): string {
    return `
<!DOCTYPE html>
<html>
<head>
  <title>Backtest Report</title>
  <style>
    body { font-family: Arial, sans-serif; margin: 20px; }
    table { border-collapse: collapse; width: 100%; }
    th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
    th { background-color: #f2f2f2; }
    .metric { margin: 10px 0; }
    .positive { color: green; }
    .negative { color: red; }
  </style>
</head>
<body>
  <h1>Backtest Performance Report</h1>
  
  <h2>Summary Statistics</h2>
  <div class="metric">Total Return: <span class="${result.summary.totalReturn >= 0 ? 'positive' : 'negative'}">${result.summary.totalReturn.toFixed(2)}%</span></div>
  <div class="metric">Sharpe Ratio: ${result.summary.sharpeRatio.toFixed(2)}</div>
  <div class="metric">Max Drawdown: <span class="negative">${result.summary.maxDrawdown.toFixed(2)}%</span></div>
  <div class="metric">Win Rate: ${result.summary.winRate.toFixed(1)}%</div>
  <div class="metric">Total Trades: ${result.summary.totalTrades}</div>
  
  <h2>Detailed Performance Metrics</h2>
  <pre>${result.performanceReport}</pre>
  
  <h2>Trade History</h2>
  <table>
    <tr>
      <th>Date</th>
      <th>Symbol</th>
      <th>Side</th>
      <th>Entry Price</th>
      <th>Exit Price</th>
      <th>Quantity</th>
      <th>P&L</th>
      <th>Return %</th>
    </tr>
    ${result.trades.map(t => `
    <tr>
      <td>${new Date(t.entryTime).toLocaleDateString()}</td>
      <td>${t.symbol}</td>
      <td>${t.side}</td>
      <td>$${t.entryPrice.toFixed(2)}</td>
      <td>$${t.exitPrice.toFixed(2)}</td>
      <td>${t.quantity}</td>
      <td class="${t.pnl >= 0 ? 'positive' : 'negative'}">$${t.pnl.toFixed(2)}</td>
      <td class="${t.returnPct >= 0 ? 'positive' : 'negative'}">${t.returnPct.toFixed(2)}%</td>
    </tr>
    `).join('')}
  </table>
</body>
</html>
    `;
  }
  
  private getOHLCData(marketData: MarketData[], symbols: string[]): Record<string, any[]> {
    const ohlcData: Record<string, any[]> = {};
    
    symbols.forEach(symbol => {
      const symbolData = marketData
        .filter(d => d.type === 'bar' && d.data.symbol === symbol)
        .map(d => ({
          time: Math.floor(d.data.timestamp / 1000), // Convert to seconds for lightweight-charts
          open: d.data.open,
          high: d.data.high,
          low: d.data.low,
          close: d.data.close,
          volume: d.data.volume
        }))
        .sort((a, b) => a.time - b.time); // Ensure data is sorted by time
      
      ohlcData[symbol] = symbolData;
    });
    
    return ohlcData;
  }
  
  private setupOrderListener(): void {
    if (this.ordersListenerSetup) return;
    
    // Listen for orders from strategy manager
    this.strategyManager.on('order', async (orderEvent: any) => {
      this.container.logger.info('[BacktestEngine] Order from StrategyManager:', orderEvent);
      this.pendingOrders.set(orderEvent.orderId, {
        ...orderEvent,
        timestamp: this.currentTime
      });
    });
    
    this.ordersListenerSetup = true;
  }
  
  private setupStrategyOrderListeners(): void {
    // Listen for orders directly from strategies
    const strategies = this.strategyManager.getAllStrategies();
    this.container.logger.info(`Setting up order listeners for ${strategies.length} strategies`);
    
    strategies.forEach(strategy => {
      this.container.logger.info(`Setting up order listener for strategy: ${strategy.config.id}`);
      
      const orderHandler = async (order: any) => {
        const orderId = `${strategy.config.id}-${Date.now()}-${Math.random()}`;
        this.container.logger.info(`[BacktestEngine] 🔔 Order from strategy ${strategy.config.id}:`, order);
        this.container.logger.info(`[BacktestEngine] Adding order ${orderId} to pendingOrders. Current size: ${this.pendingOrders.size}`);
        this.pendingOrders.set(orderId, {
          strategyId: strategy.config.id,
          orderId,
          order,
          timestamp: this.currentTime
        });
        this.container.logger.info(`[BacktestEngine] After adding, pendingOrders size: ${this.pendingOrders.size}`);
      };
      
      strategy.on('order', orderHandler);
      
      // Also listen for signals
      strategy.on('signal', (signal: any) => {
        this.container.logger.info(`[BacktestEngine] 📊 Signal from strategy ${strategy.config.id}:`, signal);
      });
    });
  }

  private async checkAndFillOrders(data: MarketData): Promise<void> {
    if (data.type !== 'bar') return;
    
    const symbol = data.data.symbol;
    const currentPrice = data.data.close;
    
    // Check pending orders for this symbol
    const ordersToFill: string[] = [];
    
    this.container.logger.info(`[checkAndFillOrders] Checking ${this.pendingOrders.size} pending orders for ${symbol}`);
    
    for (const [orderId, orderEvent] of this.pendingOrders) {
      if (orderEvent.order.symbol === symbol) {
        // For market orders, fill immediately at current price
        if (orderEvent.order.orderType === 'market') {
          this.container.logger.info(`[checkAndFillOrders] Found market order ${orderId} for ${symbol}`);
          ordersToFill.push(orderId);
        }
      }
    }
    
    // Process fills
    for (const orderId of ordersToFill) {
      const orderEvent = this.pendingOrders.get(orderId);
      if (!orderEvent) continue;
      
      const fillPrice = orderEvent.order.side === 'buy' ? 
        currentPrice * (1 + this.slippage) : 
        currentPrice * (1 - this.slippage);
      
      const fill = {
        orderId,
        symbol: orderEvent.order.symbol,
        side: orderEvent.order.side,
        quantity: orderEvent.order.quantity,
        price: fillPrice,
        timestamp: this.currentTime,
        commission: orderEvent.order.quantity * fillPrice * this.commission,
        strategyId: orderEvent.strategyId
      };
      
      this.container.logger.info(`✅ Filling ${orderEvent.order.side} order for ${symbol} @ ${fillPrice} at timestamp ${this.currentTime} (${new Date(this.currentTime).toISOString()})`);
      
      // Remove from pending BEFORE processing to avoid duplicate fills
      this.pendingOrders.delete(orderId);
      
      // Process the fill (this will update trading engine AND notify strategies)
      await this.processFill(fill);
    }
  }
  
  // Playback control methods
  async pauseBacktest(): Promise<void> {
    this.isPaused = true;
    this.container.logger.info('Backtest paused');
  }
  
  async resumeBacktest(): Promise<void> {
    this.isPaused = false;
    this.container.logger.info('Backtest resumed');
  }
  
  async stopBacktest(): Promise<void> {
    this.isRunning = false;
    this.isPaused = false;
  }
  
  setSpeedMultiplier(speed: number | null): void {
    this.speedMultiplier = speed;
    this.container.logger.info(`Backtest speed multiplier set to: ${speed === null ? 'unlimited' : speed}`);
  }
  
  getStatus(): { isRunning: boolean; isPaused: boolean; progress: number; currentTime: number } {
    const progress = this.totalEvents > 0 
      ? Math.round(((this.totalEvents - this.eventQueue.length) / this.totalEvents) * 100)
      : 0;
    
    return {
      isRunning: this.isRunning,
      isPaused: this.isPaused,
      progress,
      currentTime: this.currentTime
    };
  }
}