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 lastTradeTime = new Map<string, number>();
  private barCount = new Map<string, number>();
  private totalSignals = 0;
  
  // 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 = 1; // 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;
    
    // Update price history
    if (!this.priceHistory.has(symbol)) {
      this.priceHistory.set(symbol, []);
      this.barCount.set(symbol, 0);
      logger.info(`📊 Starting to track ${symbol} @ ${price}`);
    }
    
    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) {
      if (history && history.length % 5 === 0) {
        logger.debug(`${symbol} - Not enough history: ${history.length}/${this.SLOW_PERIOD} bars`);
      }
      return null;
    }
    
    // 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 prevHistory = history.slice(0, -1);
    const prevFastMA = this.calculateSMA(prevHistory, this.FAST_PERIOD);
    const prevSlowMA = this.calculateSMA(prevHistory, this.SLOW_PERIOD);
    
    const currentPosition = this.getPosition(symbol);
    const currentPrice = data.data.close;
    const timestamp = new Date(data.data.timestamp).toISOString().split('T')[0];
    
    // Check minimum holding period
    const currentBar = this.barCount.get(symbol) || 0;
    const lastTradeBar = this.lastTradeTime.get(symbol) || 0;
    const barsSinceLastTrade = lastTradeBar > 0 ? currentBar - lastTradeBar : Number.MAX_SAFE_INTEGER;
    
    // Detect crossovers FIRST
    const goldenCross = prevFastMA <= prevSlowMA && fastMA > slowMA;
    const deathCross = prevFastMA >= prevSlowMA && fastMA < slowMA;
    
    // Enhanced debugging - log more frequently and when MAs are close
    const maDiff = fastMA - slowMA;
    const maDiffPct = (maDiff / slowMA) * 100;
    const masAreClose = Math.abs(maDiffPct) < 1.0; // Within 1%
    
    if (history.length % this.DEBUG_INTERVAL === 0 || masAreClose || 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 trade: ${barsSinceLastTrade}`);
      
      if (goldenCross) {
        logger.info(`  🟢 GOLDEN CROSS DETECTED!`);
      }
      if (deathCross) {
        logger.info(`  🔴 DEATH CROSS DETECTED!`);
      }
    }
    
    // Note: We removed the MIN_HOLDING_BARS check here to allow closing and opening on same bar
    // The check is now done individually for new position entries
    
    if (goldenCross) {
      logger.info(`🟢 Golden cross detected for ${symbol} @ ${timestamp}`);
      logger.info(`   Current position: ${currentPosition} shares`);
      
      // For golden cross, we want to be long
      if (currentPosition < 0) {
        // Close short position first
        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) // Buy to close short
          }
        };
        
        this.lastTradeTime.set(symbol, currentBar);
        this.totalSignals++;
        logger.info(`👉 Total signals generated: ${this.totalSignals}`);
        return signal;
      } else if (currentPosition === 0) {
        // No position, open long
        logger.info(`   No current position, opening long`);
        logger.info(`   Price: ${currentPrice.toFixed(2)}, Fast MA: ${fastMA.toFixed(2)} > Slow MA: ${slowMA.toFixed(2)}`);
        logger.info(`   Prev Fast MA: ${prevFastMA.toFixed(2)} <= Prev Slow MA: ${prevSlowMA.toFixed(2)}`);
        
        // Calculate position size
        const positionSize = this.calculatePositionSize(currentPrice);
        logger.info(`   Opening long position: ${positionSize} shares`);
        
        const signal: Signal = {
          type: 'buy',
          symbol,
          strength: 0.8,
          reason: 'Golden cross - Fast MA crossed above Slow MA',
          metadata: {
            fastMA,
            slowMA,
            prevFastMA,
            prevSlowMA,
            crossoverType: 'golden',
            price: currentPrice,
            quantity: positionSize
          }
        };
        
        this.lastTradeTime.set(symbol, currentBar);
        this.totalSignals++;
        logger.info(`👉 Total signals generated: ${this.totalSignals}`);
        return signal;
      } else {
        logger.info(`   ⚠️ Already long, skipping buy signal`);
      }
    } else if (deathCross) {
      logger.info(`🔴 Death cross detected for ${symbol} @ ${timestamp}`);
      logger.info(`   Current position: ${currentPosition} shares`);
      
      // For death cross, we want to be flat or short
      if (currentPosition > 0) {
        // Close long position
        logger.info(`   Closing long position of ${currentPosition} shares`);
        logger.info(`   Price: ${currentPrice.toFixed(2)}, Fast MA: ${fastMA.toFixed(2)} < Slow MA: ${slowMA.toFixed(2)}`);
        logger.info(`   Prev Fast MA: ${prevFastMA.toFixed(2)} >= Prev Slow MA: ${prevSlowMA.toFixed(2)}`);
        
        const signal: Signal = {
          type: 'sell',
          symbol,
          strength: 0.8,
          reason: 'Death cross - Fast MA crossed below Slow MA',
          metadata: {
            fastMA,
            slowMA,
            prevFastMA,
            prevSlowMA,
            crossoverType: 'death',
            price: currentPrice,
            quantity: currentPosition
          }
        };
        
        this.lastTradeTime.set(symbol, currentBar);
        this.totalSignals++;
        logger.info(`👉 Total signals generated: ${this.totalSignals}`);
        return signal;
      } else if (currentPosition === 0) {
        // Open short position for long/short strategy
        logger.info(`   No current position, opening short`);
        
        const positionSize = this.calculatePositionSize(currentPrice);
        logger.info(`   Opening short position: ${positionSize} shares`);
        
        const signal: Signal = {
          type: 'sell',
          symbol,
          strength: 0.8,
          reason: 'Death cross - Opening short position',
          metadata: {
            fastMA,
            slowMA,
            prevFastMA,
            prevSlowMA,
            crossoverType: 'death',
            price: currentPrice,
            quantity: positionSize
          }
        };
        
        this.lastTradeTime.set(symbol, currentBar);
        this.totalSignals++;
        logger.info(`👉 Total signals generated: ${this.totalSignals}`);
        return signal;
      } else {
        logger.info(`   ⚠️ Already short, skipping sell signal`);
      }
    }
    
    // Log near-crossover conditions
    const fastApproachingSlow = Math.abs(fastMA - slowMA) / slowMA < 0.01; // Within 1%
    if (fastApproachingSlow && history.length % 20 === 0) {
      logger.debug(`${symbol} - MAs converging: Fast MA ${fastMA.toFixed(2)} ~ Slow MA ${slowMA.toFixed(2)} (${((Math.abs(fastMA - slowMA) / slowMA) * 100).toFixed(2)}% diff)`);
    }
    
    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
    let accountBalance = 100000; // Default
    try {
      if (tradingEngine.getAccountBalance) {
        accountBalance = tradingEngine.getAccountBalance();
      } else if (tradingEngine.getTotalPnl) {
        const [realized, unrealized] = tradingEngine.getTotalPnl();
        accountBalance = 100000 + realized + unrealized; // Assuming 100k initial
      }
    } 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}`);
    
    // Position tracking is handled by BaseStrategy.onOrderUpdate
    // Just log the current position
    const currentPosition = this.getPosition(symbol);
    logger.info(`Position for ${symbol}: ${currentPosition} shares`);
  }
  
  // Override to provide custom order generation
  protected async signalToOrder(signal: Signal): Promise<OrderRequest | null> {
    logger.info(`🔄 Converting signal to order:`, signal);
    
    const currentPosition = this.getPosition(signal.symbol);
    
    // Get position sizing from metadata
    const quantity = signal.metadata?.quantity || 100;
    
    if (signal.type === 'buy') {
      const order: OrderRequest = {
        symbol: signal.symbol,
        side: 'buy',
        quantity,
        orderType: 'market',
        timeInForce: 'DAY'
      };
      logger.info(`📈 Generated BUY order:`, order);
      return order;
    } else if (signal.type === 'sell') {
      const order: OrderRequest = {
        symbol: signal.symbol,
        side: 'sell',
        quantity,
        orderType: 'market',
        timeInForce: 'DAY'
      };
      logger.info(`📉 Generated SELL order:`, order);
      return order;
    }
    
    return null;
  }
}