import { IServiceContainer } from '@stock-bot/di';
import { BacktestEngine as RustEngine } from '@stock-bot/engine';
import { StorageService } from '../services/StorageService';
import { RustStrategy } from '../strategies/RustStrategy';
import { BacktestConfig } from '../types';

export interface RustBacktestConfig {
  name: string;
  symbols: string[];
  startDate: string;
  endDate: string;
  initialCapital: number;
  commission: number;
  slippage: number;
  dataFrequency: string;
}

export interface RustBacktestResult {
  config: RustBacktestConfig;
  metrics: {
    totalReturn: number;
    totalTrades: number;
    profitableTrades: number;
    winRate: number;
    profitFactor: number;
    sharpeRatio: number;
    maxDrawdown: number;
    totalPnl: number;
    avgWin: number;
    avgLoss: number;
  };
  equityCurve: Array<{ date: string; value: number }>;
  trades: any[];
  finalPositions: Record<string, any>;
}

export class RustBacktestEngine {
  private engine: RustEngine;
  private container: IServiceContainer;
  private storageService: StorageService;
  private config: RustBacktestConfig;
  
  constructor(
    container: IServiceContainer,
    storageService: StorageService,
    config: BacktestConfig
  ) {
    this.container = container;
    this.storageService = storageService;
    
    // Convert config for Rust
    const rustConfig: RustBacktestConfig = {
      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',
    };
    
    this.config = rustConfig;
    this.engine = new RustEngine(rustConfig as any);
  }
  
  /**
   * Add a TypeScript strategy to the backtest
   */
  addStrategy(strategy: RustStrategy): void {
    strategy.register(this.engine);
  }
  
  /**
   * Load historical data for the backtest
   */
  async loadData(): Promise<void> {
    // Get config from engine
    const config = this.getConfig();
    
    const startDate = new Date(config.startDate);
    const endDate = new Date(config.endDate);
    
    // Load data for each symbol
    for (const symbol of config.symbols) {
      const bars = await this.storageService.getHistoricalBars(
        symbol,
        startDate,
        endDate,
        config.dataFrequency
      );
      
      // Convert to Rust format
      const marketData = bars.map(bar => ({
        symbol,
        timestamp: bar.timestamp.getTime(), // Convert to milliseconds
        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,
      }));
      
      // Load into Rust engine
      console.log(`Loading ${marketData.length} bars for ${symbol}`);
      this.engine.loadMarketData(marketData as any);
    }
  }
  
  /**
   * Run the backtest
   */
  async run(): Promise<RustBacktestResult> {
    console.log('Starting backtest run...');
    
    // Load data first
    await this.loadData();
    
    // Run backtest in Rust
    const resultJson = await this.engine.run();
    
    // Parse result and convert snake_case to camelCase
    const rustResult = JSON.parse(resultJson);
    
    const result: RustBacktestResult = {
      config: rustResult.config,
      metrics: {
        totalReturn: rustResult.metrics.total_return,
        totalTrades: rustResult.metrics.total_trades,
        profitableTrades: rustResult.metrics.profitable_trades,
        winRate: rustResult.metrics.win_rate,
        profitFactor: rustResult.metrics.profit_factor,
        sharpeRatio: rustResult.metrics.sharpe_ratio,
        maxDrawdown: rustResult.metrics.max_drawdown,
        totalPnl: rustResult.metrics.total_pnl,
        avgWin: rustResult.metrics.avg_win,
        avgLoss: rustResult.metrics.avg_loss,
      },
      equityCurve: rustResult.equity_curve.map((point: any) => ({
        date: point[0],
        value: point[1],
      })),
      trades: rustResult.trades,
      finalPositions: rustResult.final_positions,
    };
    
    // Log results
    this.container.logger.info('Rust backtest completed', {
      totalReturn: result.metrics.totalReturn,
      totalTrades: result.metrics.totalTrades,
      sharpeRatio: result.metrics.sharpeRatio,
    });
    
    return result;
  }
  
  /**
   * Get the backtest configuration
   */
  private getConfig(): RustBacktestConfig {
    return this.config;
  }
}

/**
 * Factory function to create a Rust-powered backtest
 */
export async function createRustBacktest(
  container: IServiceContainer,
  config: BacktestConfig,
  strategies: RustStrategy[]
): Promise<RustBacktestResult> {
  const storageService = container.custom?.StorageService || new StorageService();
  
  // Create engine
  const engine = new RustBacktestEngine(container, storageService, config);
  
  // Add strategies
  for (const strategy of strategies) {
    engine.addStrategy(strategy);
  }
  
  // Run backtest
  return await engine.run();
}