import { BaseStrategy } from '../BaseStrategy';
import { Order } from '../../types';
import { TechnicalAnalysis, IncrementalIndicators, SignalGenerator, TradingSignal } from '../../indicators/TechnicalAnalysis';

interface IndicatorBasedConfig {
  symbol: string;
  initialCapital: number;
  positionSize: number;
  useRSI?: boolean;
  useMACD?: boolean;
  useBollingerBands?: boolean;
  useStochastic?: boolean;
  minSignalStrength?: number;
}

/**
 * Example strategy using multiple technical indicators from the Rust TA library
 */
export class IndicatorBasedStrategy extends BaseStrategy {
  private ta: TechnicalAnalysis;
  private incrementalIndicators: IncrementalIndicators;
  private signalGenerator: SignalGenerator;
  private priceHistory: {
    close: number[];
    high: number[];
    low: number[];
    volume: number[];
  };
  private readonly lookbackPeriod = 100; // Keep last 100 bars
  private lastSignal: TradingSignal | null = null;
  private config: IndicatorBasedConfig;

  constructor(strategyId: string, config: IndicatorBasedConfig) {
    super(strategyId, config.symbol, config.initialCapital);
    this.config = {
      useRSI: true,
      useMACD: true,
      useBollingerBands: true,
      useStochastic: true,
      minSignalStrength: 0.6,
      ...config
    };
    
    this.ta = new TechnicalAnalysis();
    this.incrementalIndicators = new IncrementalIndicators();
    this.signalGenerator = new SignalGenerator();
    
    this.priceHistory = {
      close: [],
      high: [],
      low: [],
      volume: []
    };

    // Initialize incremental indicators for real-time updates
    this.incrementalIndicators.createSMA('sma20', 20);
    this.incrementalIndicators.createSMA('sma50', 50);
    this.incrementalIndicators.createEMA('ema12', 12);
    this.incrementalIndicators.createEMA('ema26', 26);
    this.incrementalIndicators.createRSI('rsi14', 14);
  }

  onMarketData(data: any): Order | null {
    const { timestamp } = data;
    
    // Update price history
    if ('close' in data && 'high' in data && 'low' in data) {
      this.priceHistory.close.push(data.close);
      this.priceHistory.high.push(data.high);
      this.priceHistory.low.push(data.low);
      this.priceHistory.volume.push(data.volume || 0);
      
      // Trim to lookback period
      if (this.priceHistory.close.length > this.lookbackPeriod) {
        this.priceHistory.close.shift();
        this.priceHistory.high.shift();
        this.priceHistory.low.shift();
        this.priceHistory.volume.shift();
      }

      // Update incremental indicators
      this.incrementalIndicators.update('sma20', data.close);
      this.incrementalIndicators.update('sma50', data.close);
      this.incrementalIndicators.update('ema12', data.close);
      this.incrementalIndicators.update('ema26', data.close);
      this.incrementalIndicators.update('rsi14', data.close);
    }
    
    // Need enough data for indicators
    if (this.priceHistory.close.length < 26) {
      return null;
    }
    
    // Generate trading signals
    const signal = this.signalGenerator.generateSignals(
      this.symbol,
      this.priceHistory,
      timestamp
    );
    
    this.lastSignal = signal;
    
    // Log signal for debugging
    if (signal.action !== 'HOLD') {
      console.log(`[${new Date(timestamp).toISOString()}] Signal: ${signal.action} (strength: ${signal.strength.toFixed(2)}) - ${signal.reason}`);
    }
    
    // Check if signal is strong enough
    if (signal.strength < this.config.minSignalStrength) {
      return null;
    }
    
    // Generate orders based on signals and position
    const currentPosition = this.positions[this.symbol] || 0;
    
    if (signal.action === 'BUY' && currentPosition <= 0) {
      // Close short position if any
      if (currentPosition < 0) {
        return this.createOrder('market', 'buy', Math.abs(currentPosition));
      }
      // Open long position
      return this.createOrder('market', 'buy', this.config.positionSize);
    } else if (signal.action === 'SELL' && currentPosition >= 0) {
      // Close long position if any
      if (currentPosition > 0) {
        return this.createOrder('market', 'sell', Math.abs(currentPosition));
      }
      // Open short position (if allowed)
      // return this.createOrder('market', 'sell', this.config.positionSize);
    }
    
    return null;
  }

  getState() {
    const incrementalValues: Record<string, number | null> = {
      sma20: this.incrementalIndicators.current('sma20'),
      sma50: this.incrementalIndicators.current('sma50'),
      ema12: this.incrementalIndicators.current('ema12'),
      ema26: this.incrementalIndicators.current('ema26'),
      rsi14: this.incrementalIndicators.current('rsi14')
    };

    return {
      ...super.getState(),
      priceHistoryLength: this.priceHistory.close.length,
      incrementalIndicators: incrementalValues,
      lastSignal: this.lastSignal,
      config: this.config
    };
  }

  /**
   * Example of using batch indicator calculation
   */
  analyzeHistoricalData(): void {
    if (this.priceHistory.close.length < 50) {
      console.log('Not enough data for historical analysis');
      return;
    }

    const closes = this.priceHistory.close;
    
    // Calculate various indicators
    const sma20 = this.ta.sma(closes, 20);
    const sma50 = this.ta.sma(closes, 50);
    const rsi = this.ta.rsi(closes, 14);
    const macd = this.ta.macd(closes);
    const bb = this.ta.bollingerBands(closes, 20, 2);
    const atr = this.ta.atr(
      this.priceHistory.high,
      this.priceHistory.low,
      this.priceHistory.close,
      14
    );

    // Latest values
    const currentPrice = closes[closes.length - 1];
    const currentSMA20 = TechnicalAnalysis.latest(sma20);
    const currentSMA50 = TechnicalAnalysis.latest(sma50);
    const currentRSI = TechnicalAnalysis.latest(rsi);
    const currentATR = TechnicalAnalysis.latest(atr);

    console.log('Historical Analysis:');
    console.log(`Current Price: ${currentPrice}`);
    console.log(`SMA20: ${currentSMA20?.toFixed(2)}`);
    console.log(`SMA50: ${currentSMA50?.toFixed(2)}`);
    console.log(`RSI: ${currentRSI?.toFixed(2)}`);
    console.log(`ATR: ${currentATR?.toFixed(2)}`);
    console.log(`MACD: ${TechnicalAnalysis.latest(macd.macd)?.toFixed(2)}`);
    console.log(`BB %B: ${((currentPrice - TechnicalAnalysis.latest(bb.lower)!) / (TechnicalAnalysis.latest(bb.upper)! - TechnicalAnalysis.latest(bb.lower)!)).toFixed(2)}`);
  }
}