import { IServiceContainer } from '@stock-bot/di';
import { BacktestEngine as RustEngine } from '@stock-bot/engine';
import { EventEmitter } from 'events';
import { StorageService } from '../services/StorageService';
import { SMACrossoverStrategy, StrategyExecutor } from '../strategies/StrategyExecutor';
import { BacktestConfig, BacktestResult } from '../types';

/**
 * Adapter that bridges the orchestrator with the Rust backtest engine
 */
export class RustBacktestAdapter extends EventEmitter {
  private container: IServiceContainer;
  private storageService: StorageService;
  private currentEngine?: RustEngine;
  private isRunning = false;
  private strategyExecutor: StrategyExecutor;

  constructor(container: IServiceContainer) {
    super();
    this.container = container;
    this.storageService = container.custom?.StorageService || new StorageService(
      container,
      container.mongodb,
      container.postgres,
      null
    );
    this.strategyExecutor = new StrategyExecutor();
  }

  async runBacktest(config: BacktestConfig): Promise<BacktestResult> {
    if (this.isRunning) {
      throw new Error('Backtest already running');
    }

    this.isRunning = true;
    const startTime = Date.now();

    try {
      this.container.logger.info('Starting Rust backtest engine', {
        symbols: config.symbols,
        startDate: config.startDate,
        endDate: config.endDate,
      });

      // Create Rust engine configuration
      const rustConfig = {
        name: config.name || 'Backtest',
        symbols: config.symbols,
        startDate: config.startDate,
        endDate: config.endDate,
        initialCapital: config.initialCapital,
        commission: config.commission ?? 0.001,
        slippage: config.slippage ?? 0.0001,
        dataFrequency: config.dataFrequency || '1d',
      };

      // Create new Rust engine instance
      this.currentEngine = new RustEngine(rustConfig);

      // For now, use a simple strategy mapping
      // In the future, strategies should be written in Rust or use a common interface
      this.container.logger.info('About to register strategy', {
        strategy: config.strategy,
        config: config.config
      });
      this.registerStrategy(config.strategy, config.config || {});

      // Load historical data
      await this.loadHistoricalData(config);

      // Emit progress events
      this.emit('progress', {
        progress: 0.1,
        message: 'Data loaded, starting backtest...',
      });

      // Run the backtest in Rust
      this.container.logger.info('Starting Rust engine execution');
      const resultJson = this.currentEngine.run();
      this.container.logger.info('Rust engine execution completed');
      const rustResult = JSON.parse(resultJson);
      
      this.container.logger.info('Rust backtest result summary', {
        totalTrades: rustResult.metrics?.total_trades,
        equityCurveLength: rustResult.equity_curve?.length,
        tradesLength: rustResult.trades?.length,
        finalPositions: rustResult.final_positions
      });
      
      // Log first trade structure to understand format
      if (rustResult.trades?.length > 0) {
        this.container.logger.info('First trade structure:', rustResult.trades[0]);
      }

      // Rust result already contains OHLC data from the engine
      const result: BacktestResult = rustResult;

      this.emit('complete', result);
      return result;

    } catch (error) {
      this.container.logger.error('Rust backtest failed', error);
      
      const errorResult: BacktestResult = {
        backtestId: `rust-${Date.now()}`,
        status: 'failed',
        completedAt: new Date().toISOString(),
        config: {
          name: config.name || 'Backtest',
          strategy: config.strategy,
          symbols: config.symbols,
          startDate: config.startDate,
          endDate: config.endDate,
          initialCapital: config.initialCapital,
          commission: config.commission ?? 0.001,
          slippage: config.slippage ?? 0.0001,
          dataFrequency: config.dataFrequency || '1d',
        },
        metrics: this.getEmptyMetrics(),
        equityCurve: [],
        trades: [],
        dailyReturns: [],
        finalPositions: {},
        executionTime: Date.now() - startTime,
        error: error instanceof Error ? error.message : 'Unknown error',
      };

      this.emit('error', error);
      return errorResult;

    } finally {
      this.isRunning = false;
      this.currentEngine = undefined;
    }
  }

  async stopBacktest(): Promise<void> {
    if (!this.isRunning) {
      throw new Error('No backtest running');
    }

    // In future, implement proper cancellation in Rust
    this.isRunning = false;
    this.emit('cancelled');
  }

  private async loadHistoricalData(config: BacktestConfig): Promise<void> {
    const startDate = new Date(config.startDate);
    const endDate = new Date(config.endDate);
    const allMarketData = [];

    // Collect all data for all symbols
    for (const symbol of config.symbols) {
      const bars = await this.storageService.getHistoricalBars(
        symbol,
        startDate,
        endDate,
        config.dataFrequency || '1d'
      );

      // Convert to Rust format
      const marketData = bars.map(bar => ({
        symbol,
        timestamp: bar.timestamp.getTime(),
        type: 'bar',
        open: bar.open,
        high: bar.high,
        low: bar.low,
        close: bar.close,
        volume: bar.volume,
        vwap: bar.vwap || (bar.high + bar.low + bar.close) / 3,
      }));

      allMarketData.push(...marketData);
      this.container.logger.info(`Collected ${marketData.length} bars for ${symbol}`);
    }

    // Sort all data by timestamp to ensure chronological order
    allMarketData.sort((a, b) => a.timestamp - b.timestamp);

    // Load all data at once into Rust engine
    if (this.currentEngine) {
      this.container.logger.info(`Loading ${allMarketData.length} total bars into Rust engine`);
      this.currentEngine.loadMarketData(allMarketData);
    }
  }

  private registerStrategy(strategyName: string, parameters: any): void {
    if (!this.currentEngine) {return;}

    this.container.logger.info('Registering strategy', {
      strategyName,
      parameters
    });

    // Check if we should use TypeScript or native Rust implementation
    const useTypeScript = parameters.useTypeScriptImplementation || false;
    
    if (useTypeScript) {
      // Register TypeScript strategy
      this.container.logger.info('Using TypeScript strategy implementation');
      
      // For now, we'll use the SMACrossoverStrategy
      if (strategyName.toLowerCase().includes('sma') || strategyName.toLowerCase().includes('crossover')) {
        const strategyId = `strategy-${Date.now()}`;
        this.strategyExecutor.registerStrategy(strategyId, SMACrossoverStrategy);
        
        // Create a callback that uses the strategy executor
        const callback = (callJson: string) => {
          try {
            const call = JSON.parse(callJson);
            
            if (call.method === 'on_market_data') {
              const signals = this.strategyExecutor.onMarketData(call.data);
              return JSON.stringify({ signals });
            } else if (call.method === 'on_fill') {
              const { symbol, quantity, price, side } = call.data;
              this.strategyExecutor.onFill(symbol, quantity, price, side);
              return JSON.stringify({ signals: [] });
            }
            
            return JSON.stringify({ signals: [] });
          } catch (error) {
            this.container.logger.error('Strategy execution error:', error);
            return JSON.stringify({ signals: [] });
          }
        };
        
        // Register with Rust engine
        this.currentEngine.addTypescriptStrategy(
          strategyName,
          strategyId,
          parameters,
          callback
        );
      }
    } else {
      // Use native Rust strategy for maximum performance
      this.container.logger.info('Using native Rust strategy implementation');
      
      // Map strategy names to their Rust strategy types
      let strategyType = 'sma_crossover'; // default
      
      if (strategyName.toLowerCase().includes('mean') || strategyName.toLowerCase().includes('reversion')) {
        strategyType = 'mean_reversion';
      } else if (strategyName.toLowerCase().includes('momentum')) {
        strategyType = 'momentum';
      } else if (strategyName.toLowerCase().includes('pairs')) {
        strategyType = 'pairs_trading';
      } else if (strategyName.toLowerCase().includes('sma') || strategyName.toLowerCase().includes('crossover')) {
        strategyType = 'sma_crossover';
      }
      
      this.container.logger.info(`Mapped strategy '${strategyName}' to type '${strategyType}'`);
      
      // Use the addNativeStrategy method instead
      this.currentEngine.addNativeStrategy(
        strategyType,
        strategyName,
        `strategy-${Date.now()}`,
        parameters
      );
    }
  }

}