import { IServiceContainer } from '@stock-bot/di';
import { TradingEngine } from '@stock-bot/engine';
import { EventEmitter } from 'events';
import { MarketData, OrderRequest, StrategyConfig } from '../types';
import { BaseStrategy } from './BaseStrategy';

export class StrategyManager extends EventEmitter {
  private strategies = new Map<string, BaseStrategy>();
  private activeStrategies = new Set<string>();
  private tradingEngine: TradingEngine | null = null;
  private container: IServiceContainer;

  constructor(container: IServiceContainer) {
    super();
    this.container = container;
  }

  setupEventListeners(): void {
    const marketDataService = this.container.custom?.MarketDataService;
    const executionService = this.container.custom?.ExecutionService;
    
    if (!marketDataService || !executionService) {
      this.container.logger.error('Required services not found in container');
      return;
    }
    
    // Listen for market data
    marketDataService.on('marketData', (data: MarketData) => {
      this.handleMarketData(data);
    });

    // Listen for market data batches (more efficient)
    marketDataService.on('marketDataBatch', (batch: MarketData[]) => {
      this.handleMarketDataBatch(batch);
    });

    // Listen for fills
    executionService.on('fill', (fill: any) => {
      this.handleFill(fill);
    });
  }

  async initializeStrategies(configs: StrategyConfig[]): Promise<void> {
    // Clear existing strategies
    for (const [id, strategy] of this.strategies) {
      await strategy.shutdown();
    }
    this.strategies.clear();
    this.activeStrategies.clear();

    // Get trading engine from mode manager
    const modeManager = this.container.custom?.ModeManager;
    if (modeManager) {
      this.tradingEngine = modeManager.getTradingEngine();
    }

    // Initialize new strategies
    for (const config of configs) {
      try {
        const strategy = await this.createStrategy(config);
        this.strategies.set(config.id, strategy);
        
        if (config.enabled) {
          await this.enableStrategy(config.id);
        }
        
        this.container.logger.info(`Initialized strategy: ${config.name} (${config.id})`);
      } catch (error) {
        this.container.logger.error(`Failed to initialize strategy ${config.name}:`, error);
      }
    }
  }

  private async createStrategy(config: StrategyConfig): Promise<BaseStrategy> {
    // Load strategy based on name
    let strategy: BaseStrategy;
    
    switch (config.name.toLowerCase()) {
      case 'meanreversion':
      case 'mean-reversion': {
        const { MeanReversionStrategy } = await import('./examples/MeanReversionStrategy');
        strategy = new MeanReversionStrategy(
          config,
          this.container.custom?.ModeManager,
          this.container.custom?.ExecutionService
        );
        break;
      }
      case 'smacrossover':
      case 'sma-crossover':
      case 'moving-average': {
        const { SimpleMovingAverageCrossover } = await import('./examples/SimpleMovingAverageCrossoverFixed');
        strategy = new SimpleMovingAverageCrossover(
          config,
          this.container.custom?.ModeManager,
          this.container.custom?.ExecutionService
        );
        break;
      }
      case 'mlenhanced':
      case 'ml-enhanced': {
        const { MLEnhancedStrategy } = await import('./examples/MLEnhancedStrategy');
        strategy = new MLEnhancedStrategy(
          config,
          this.container.custom?.ModeManager,
          this.container.custom?.ExecutionService
        );
        break;
      }
      default:
        // Default to base strategy
        this.container.logger.warn(`Unknown strategy: ${config.name}, using base strategy`);
        strategy = new BaseStrategy(
          config,
          this.container.custom?.ModeManager,
          this.container.custom?.ExecutionService
        );
        break;
    }
    
    // Set up strategy event handlers
    strategy.on('signal', (signal: any) => {
      this.handleStrategySignal(config.id, signal);
    });
    
    strategy.on('order', (order: any) => {
      this.handleStrategyOrder(config.id, order);
    });
    
    strategy.on('error', (error: Error) => {
      this.container.logger.error(`Strategy ${config.id} error:`, error);
    });
    
    return strategy;
  }

  async enableStrategy(strategyId: string): Promise<void> {
    const strategy = this.strategies.get(strategyId);
    if (!strategy) {
      throw new Error(`Strategy ${strategyId} not found`);
    }

    await strategy.initialize();
    await strategy.start(); // Start the strategy to make it active
    this.activeStrategies.add(strategyId);
    this.container.logger.info(`Enabled strategy: ${strategyId}`);
  }

  async disableStrategy(strategyId: string): Promise<void> {
    const strategy = this.strategies.get(strategyId);
    if (!strategy) {
      throw new Error(`Strategy ${strategyId} not found`);
    }

    await strategy.shutdown();
    this.activeStrategies.delete(strategyId);
    this.container.logger.info(`Disabled strategy: ${strategyId}`);
  }

  async onMarketData(data: MarketData): Promise<void> {
    return this.handleMarketData(data);
  }

  private async handleMarketData(data: MarketData): Promise<void> {
    // Forward to all active strategies
    if (this.activeStrategies.size === 0) {
      this.container.logger.info(`[StrategyManager] No active strategies to process market data! All strategies: ${Array.from(this.strategies.keys()).join(', ')}`);
    } else {
      this.container.logger.info(`[StrategyManager] Forwarding market data to ${this.activeStrategies.size} active strategies: ${Array.from(this.activeStrategies).join(', ')}`);
    }
    
    for (const strategyId of this.activeStrategies) {
      const strategy = this.strategies.get(strategyId);
      if (strategy) {
        try {
          await strategy.onMarketData(data);
        } catch (error) {
          this.container.logger.error(`Error processing market data for strategy ${strategyId}:`, error);
        }
      }
    }
  }

  private async handleMarketDataBatch(batch: MarketData[]): Promise<void> {
    // Process batch more efficiently
    for (const strategyId of this.activeStrategies) {
      const strategy = this.strategies.get(strategyId);
      if (strategy) {
        try {
          await strategy.onMarketDataBatch(batch);
        } catch (error) {
          this.container.logger.error(`Error processing market data batch for strategy ${strategyId}:`, error);
        }
      }
    }
  }

  private async handleFill(fill: any): Promise<void> {
    // Forward fill to the strategy that created the order
    for (const [strategyId, strategy] of this.strategies) {
      if (strategy.hasOrder(fill.orderId)) {
        try {
          await strategy.onFill(fill);
        } catch (error) {
          this.container.logger.error(`Error processing fill for strategy ${strategyId}:`, error);
        }
        break;
      }
    }
  }

  private async handleStrategySignal(strategyId: string, signal: any): Promise<void> {
    this.container.logger.info(`Strategy ${strategyId} generated signal:`, signal);
    // Signals are informational - strategies will convert strong signals to orders
  }
  
  private async handleStrategyOrder(strategyId: string, order: OrderRequest): Promise<void> {
    this.container.logger.info(`Strategy ${strategyId} generated order:`, order);
    
    // Submit order through trading engine (for backtesting)
    if (this.tradingEngine) {
      try {
        // Create order object for Rust API
        const orderObj = {
          id: `${strategyId}-${Date.now()}`,
          symbol: order.symbol,
          side: order.side,
          quantity: order.quantity,
          orderType: order.orderType,
          limitPrice: order.limitPrice,
          timeInForce: order.timeInForce || 'DAY'
        };
        
        const orderResult = await this.tradingEngine.submitOrder(orderObj);
        const result = JSON.parse(orderResult);
        this.container.logger.info(`Order placed for strategy ${strategyId}: ${result.order_id}`);
        
        // Emit order event
        this.emit('order', {
          strategyId,
          orderId: result.order_id,
          order
        });
      } catch (error) {
        this.container.logger.error(`Failed to place order for strategy ${strategyId}:`, error);
      }
    } else {
      // Use execution service for paper/live trading
      const executionService = this.container.custom?.ExecutionService;
      if (executionService) {
        try {
          const result = await executionService.submitOrder(order);
          this.container.logger.info(`Order submitted for strategy ${strategyId}:`, result);
        } catch (error) {
          this.container.logger.error(`Failed to submit order for strategy ${strategyId}:`, error);
        }
      }
    }
  }

  async onMarketData(data: MarketData): Promise<void> {
    await this.handleMarketData(data);
  }

  getTradingEngine(): TradingEngine | null {
    return this.tradingEngine;
  }

  getActiveStrategies(): string[] {
    return Array.from(this.activeStrategies);
  }

  getStrategy(strategyId: string): BaseStrategy | undefined {
    return this.strategies.get(strategyId);
  }
  
  getAllStrategies(): BaseStrategy[] {
    return Array.from(this.strategies.values());
  }

  async shutdown(): Promise<void> {
    this.container.logger.info('Shutting down strategy manager...');
    
    // Disable all strategies
    for (const strategyId of this.activeStrategies) {
      await this.disableStrategy(strategyId);
    }
    
    // Clear all strategies
    this.strategies.clear();
    this.activeStrategies.clear();
    this.tradingEngine = null;
  }
}