import { BaseStrategy, Signal } from '../BaseStrategy';
import { MarketData } from '../../types';
import { getLogger } from '@stock-bot/logger';

const logger = getLogger('SimpleMovingAverageCrossover');

export class SimpleMovingAverageCrossover extends BaseStrategy {
  private priceHistory = new Map<string, number[]>();
  private lastSignalBar = new Map<string, number>();
  private barCount = new Map<string, number>();
  private totalSignals = 0;
  private lastCrossoverType = new Map<string, 'golden' | 'death' | null>();
  
  // Strategy parameters
  private readonly FAST_PERIOD = 5;  // Changed from 10 to generate more signals
  private readonly SLOW_PERIOD = 15; // Changed from 20 to generate more signals
  private readonly POSITION_SIZE = 0.1; // 10% of capital per position
  private readonly MIN_HOLDING_BARS = 3; // Minimum bars to hold position
  private readonly DEBUG_INTERVAL = 10; // Log every N bars for debugging
  
  constructor(config: any, modeManager?: any, executionService?: any) {
    super(config, modeManager, executionService);
    logger.info(`SimpleMovingAverageCrossover initialized with Fast=${this.FAST_PERIOD}, Slow=${this.SLOW_PERIOD}`);
  }
  
  protected updateIndicators(data: MarketData): void {
    if (data.type !== 'bar') return;
    
    const symbol = data.data.symbol;
    const price = data.data.close;
    
    // Initialize or get price history
    if (!this.priceHistory.has(symbol)) {
      this.priceHistory.set(symbol, []);
      this.barCount.set(symbol, 0);
      logger.info(`📊 Starting to track ${symbol} @ ${price.toFixed(2)}`);
    }
    
    const history = this.priceHistory.get(symbol)!;
    history.push(price);
    
    // Increment bar count
    const currentBar = (this.barCount.get(symbol) || 0) + 1;
    this.barCount.set(symbol, currentBar);
    
    // Keep only needed history
    if (history.length > this.SLOW_PERIOD * 2) {
      history.shift();
    }
    
    // Log when we have enough data to start trading
    if (history.length === this.SLOW_PERIOD) {
      logger.info(`✅ ${symbol} now has enough history (${history.length} bars) to start trading`);
    }
  }

  protected async generateSignal(data: MarketData): Promise<Signal | null> {
    if (data.type !== 'bar') return null;
    
    const symbol = data.data.symbol;
    const history = this.priceHistory.get(symbol);
    
    if (!history || history.length < this.SLOW_PERIOD) {
      return null;
    }
    
    const currentPrice = data.data.close;
    const timestamp = data.data.timestamp;
    const currentBar = this.barCount.get(symbol) || 0;
    
    // Calculate moving averages
    const fastMA = this.calculateSMA(history, this.FAST_PERIOD);
    const slowMA = this.calculateSMA(history, this.SLOW_PERIOD);
    
    // Get previous MAs for crossover detection
    const historyWithoutLast = history.slice(0, -1);
    const prevFastMA = this.calculateSMA(historyWithoutLast, this.FAST_PERIOD);
    const prevSlowMA = this.calculateSMA(historyWithoutLast, this.SLOW_PERIOD);
    
    // Detect crossovers
    const goldenCross = prevFastMA <= prevSlowMA && fastMA > slowMA;
    const deathCross = prevFastMA >= prevSlowMA && fastMA < slowMA;
    
    // Get current position
    const currentPosition = this.getPosition(symbol);
    
    // Track last signal bar
    const lastSignalBar = this.lastSignalBar.get(symbol) || 0;
    const barsSinceLastSignal = currentBar - lastSignalBar;
    
    // Calculate MA difference for debugging
    const maDiff = fastMA - slowMA;
    const maDiffPct = (maDiff / slowMA) * 100;
    
    // Debug logging every N bars
    if (currentBar % this.DEBUG_INTERVAL === 0 || goldenCross || deathCross) {
      logger.info(`${symbol} @ ${timestamp} [Bar ${currentBar}]:`);
      logger.info(`  Price: $${currentPrice.toFixed(2)}`);
      logger.info(`  Fast MA (${this.FAST_PERIOD}): $${fastMA.toFixed(2)}`);
      logger.info(`  Slow MA (${this.SLOW_PERIOD}): $${slowMA.toFixed(2)}`);
      logger.info(`  MA Diff: ${maDiff.toFixed(2)} (${maDiffPct.toFixed(2)}%)`);
      logger.info(`  Position: ${currentPosition} shares`);
      logger.info(`  Bars since last signal: ${barsSinceLastSignal}`);
      
      if (goldenCross) {
        logger.info(`  🟢 GOLDEN CROSS DETECTED!`);
      }
      if (deathCross) {
        logger.info(`  🔴 DEATH CROSS DETECTED!`);
      }
    }
    
    // Store crossover type for position management
    if (goldenCross) {
      this.lastCrossoverType.set(symbol, 'golden');
    } else if (deathCross) {
      this.lastCrossoverType.set(symbol, 'death');
    }
    
    // Check if we should enter a position based on the current trend
    const lastCrossover = this.lastCrossoverType.get(symbol);
    
    if (currentPosition === 0 && barsSinceLastSignal >= this.MIN_HOLDING_BARS) {
      // No position - check if we should enter based on last crossover
      if (lastCrossover === 'golden' && fastMA > slowMA) {
        // Trend is still bullish after golden cross - open long
        logger.info(`🟢 Opening LONG position - Bullish trend after golden cross`);
        logger.info(`   Current position: 0 shares`);
        
        const positionSize = this.calculatePositionSize(currentPrice);
        logger.info(`   Opening long position: ${positionSize} shares`);
        
        const signal: Signal = {
          type: 'buy',
          symbol,
          strength: 0.8,
          reason: 'Bullish trend - Opening long position',
          metadata: {
            fastMA,
            slowMA,
            prevFastMA,
            prevSlowMA,
            crossoverType: 'trend_long',
            price: currentPrice,
            quantity: positionSize
          }
        };
        
        this.lastSignalBar.set(symbol, currentBar);
        this.totalSignals++;
        logger.info(`👉 Total signals generated: ${this.totalSignals}`);
        return signal;
        
      } else if (lastCrossover === 'death' && fastMA < slowMA) {
        // Trend is still bearish after death cross - open short
        logger.info(`🔴 Opening SHORT position - Bearish trend after death cross`);
        logger.info(`   Current position: 0 shares`);
        
        const positionSize = this.calculatePositionSize(currentPrice);
        logger.info(`   Opening short position: ${positionSize} shares`);
        
        const signal: Signal = {
          type: 'sell',
          symbol,
          strength: 0.8,
          reason: 'Bearish trend - Opening short position',
          metadata: {
            fastMA,
            slowMA,
            prevFastMA,
            prevSlowMA,
            crossoverType: 'trend_short',
            price: currentPrice,
            quantity: positionSize
          }
        };
        
        this.lastSignalBar.set(symbol, currentBar);
        this.totalSignals++;
        logger.info(`👉 Total signals generated: ${this.totalSignals}`);
        return signal;
      }
    }
    
    // Handle crossovers for position changes
    if (goldenCross) {
      logger.info(`🟢 Golden cross detected for ${symbol} @ ${timestamp}`);
      logger.info(`   Current position: ${currentPosition} shares`);
      
      if (currentPosition < 0) {
        // Close short position
        logger.info(`   Closing short position of ${Math.abs(currentPosition)} shares`);
        const signal: Signal = {
          type: 'buy',
          symbol,
          strength: 0.8,
          reason: 'Golden cross - Closing short position',
          metadata: {
            fastMA,
            slowMA,
            prevFastMA,
            prevSlowMA,
            crossoverType: 'golden',
            price: currentPrice,
            quantity: Math.abs(currentPosition)
          }
        };
        
        this.lastSignalBar.set(symbol, currentBar);
        this.totalSignals++;
        logger.info(`👉 Total signals generated: ${this.totalSignals}`);
        return signal;
      }
    } else if (deathCross) {
      logger.info(`🔴 Death cross detected for ${symbol} @ ${timestamp}`);
      logger.info(`   Current position: ${currentPosition} shares`);
      
      if (currentPosition > 0) {
        // Close long position
        logger.info(`   Closing long position of ${currentPosition} shares`);
        const signal: Signal = {
          type: 'sell',
          symbol,
          strength: 0.8,
          reason: 'Death cross - Closing long position',
          metadata: {
            fastMA,
            slowMA,
            prevFastMA,
            prevSlowMA,
            crossoverType: 'death',
            price: currentPrice,
            quantity: currentPosition
          }
        };
        
        this.lastSignalBar.set(symbol, currentBar);
        this.totalSignals++;
        logger.info(`👉 Total signals generated: ${this.totalSignals}`);
        return signal;
      }
    }
    
    return null;
  }

  private calculateSMA(prices: number[], period: number): number {
    if (prices.length < period) {
      logger.warn(`Not enough data for SMA calculation: ${prices.length} < ${period}`);
      return 0;
    }
    
    const slice = prices.slice(-period);
    const sum = slice.reduce((a, b) => a + b, 0);
    const sma = sum / period;
    
    // Sanity check
    if (isNaN(sma) || !isFinite(sma)) {
      logger.error(`Invalid SMA calculation: sum=${sum}, period=${period}, prices=${slice.length}`);
      return 0;
    }
    
    return sma;
  }
  
  private calculatePositionSize(price: number): number {
    // Get account balance from trading engine
    const tradingEngine = this.modeManager?.getTradingEngine();
    if (!tradingEngine) {
      logger.warn('No trading engine available, using default position size');
      return 100;
    }
    
    // Try to get account balance from trading engine
    // Use initial capital from config parameters if available
    let accountBalance = this.config.parameters?.initialCapital || 100000;
    try {
      if (tradingEngine.getAccountBalance) {
        accountBalance = tradingEngine.getAccountBalance();
      } else if (tradingEngine.getTotalPnl) {
        const [realized, unrealized] = tradingEngine.getTotalPnl();
        accountBalance = (this.config.parameters?.initialCapital || 100000) + realized + unrealized;
      }
    } catch (error) {
      logger.warn('Could not get account balance:', error);
    }
    
    const positionValue = accountBalance * this.POSITION_SIZE;
    const shares = Math.floor(positionValue / price);
    
    logger.debug(`Position sizing: Balance=$${accountBalance}, Position Size=${this.POSITION_SIZE}, Price=$${price}, Shares=${shares}`);
    
    return Math.max(1, shares); // At least 1 share
  }
  
  protected onOrderFilled(fill: any): void {
    const { symbol, side, quantity, price } = fill;
    
    logger.info(`✅ ${side.toUpperCase()} filled: ${symbol} - ${quantity} shares @ ${price}`);
    
    // Update our internal position tracking to match
    // This is redundant with BaseStrategy but helps with debugging
    const currentPosition = this.getPosition(symbol);
    logger.info(`   Position after fill: ${currentPosition} shares`);
  }
}