/**
 * Playbook Generator
 * Auto-detects repeatable patterns from daily post-mortem data
 */

import { rawQuery } from '../db.js';

/**
 * Detect patterns and generate playbooks
 * @param {Object} options - Query options
 * @returns {Promise<Array>} Array of detected patterns/playbooks
 */
export async function generatePlaybooks(options = {}) {
  const {
    lookbackDays = 90,
    minOccurrences = 5,
    minWinRate = 0.60
  } = options;
  
  // Pattern 1: FDA Approval Squeeze
  const fdaPattern = await detectFDAPattern(lookbackDays, minOccurrences);
  
  // Pattern 2: Earnings Beat Fade
  const earningsPattern = await detectEarningsFadePattern(lookbackDays, minOccurrences);
  
  // Pattern 3: Pre-market Gap Continuation
  const gapContinuationPattern = await detectGapContinuationPattern(lookbackDays, minOccurrences);
  
  // Pattern 4: Options Flow Pre-Positioning
  const prePositioningPattern = await detectPrePositioningPattern(lookbackDays, minOccurrences);
  
  // Combine and filter by win rate
  const allPatterns = [
    fdaPattern,
    earningsPattern,
    gapContinuationPattern,
    prePositioningPattern
  ].filter(p => p && p.winRate >= minWinRate);
  
  // Sort by win rate and expectancy
  allPatterns.sort((a, b) => {
    const aScore = a.winRate * a.expectancy;
    const bScore = b.winRate * b.expectancy;
    return bScore - aScore;
  });
  
  return allPatterns.slice(0, 10); // Top 10 patterns
}

/**
 * Detect FDA Approval Squeeze pattern
 */
async function detectFDAPattern(lookbackDays, minOccurrences) {
  try {
    const query = `
      WITH pattern_matches AS (
        SELECT 
          symbol,
          trade_date,
          first_cross_session,
          max_abs_pct_rth,
          max_abs_pct_pre,
          opt_notional_bull,
          opt_notional_bear,
          daily_pct_change,
          news_fda
        FROM (
          SELECT * FROM public.intraday_option_factors
          WHERE trade_date >= CURRENT_DATE - INTERVAL '${lookbackDays} days'
        ) factors
        WHERE news_fda = 1
          AND first_cross_session = 'PRE'
          AND opt_notional_bull > 2 * COALESCE(opt_notional_bear, 1)
          AND max_abs_pct_rth > max_abs_pct_pre
      ),
      outcomes AS (
        SELECT 
          pm.*,
          CASE 
            WHEN pm.daily_pct_change >= 3 THEN 'WIN'
            WHEN pm.daily_pct_change <= -2 THEN 'LOSS'
            ELSE 'NEUTRAL'
          END AS outcome
        FROM pattern_matches pm
      )
      SELECT 
        COUNT(*) AS total_occurrences,
        SUM(CASE WHEN outcome = 'WIN' THEN 1 ELSE 0 END) AS wins,
        SUM(CASE WHEN outcome = 'LOSS' THEN 1 ELSE 0 END) AS losses,
        AVG(CASE WHEN outcome = 'WIN' THEN daily_pct_change ELSE NULL END) AS avg_win,
        AVG(CASE WHEN outcome = 'LOSS' THEN daily_pct_change ELSE NULL END) AS avg_loss
      FROM outcomes
      WHERE outcome != 'NEUTRAL'
    `;
    
    const result = await rawQuery(query);
    
    if (!result || result.length === 0 || result[0].total_occurrences < minOccurrences) {
      return null;
    }
    
    const row = result[0];
    const total = parseInt(row.total_occurrences) || 0;
    const wins = parseInt(row.wins) || 0;
    const losses = parseInt(row.losses) || 0;
    const winRate = total > 0 ? wins / total : 0;
    const avgWin = parseFloat(row.avg_win) || 0;
    const avgLoss = parseFloat(row.avg_loss) || 0;
    const expectancy = (winRate * avgWin) + ((1 - winRate) * avgLoss);
    
    return {
      name: 'FDA Approval Squeeze',
      description: 'FDA approval with pre-market gap, bullish options, and RTH continuation',
      criteria: {
        news_fda: 1,
        first_cross_session: 'PRE',
        opt_notional_bull: '> 2x bear',
        max_abs_pct_rth: '> max_abs_pct_pre (continuation into RTH)'
      },
      totalOccurrences: total,
      wins,
      losses,
      winRate: Math.round(winRate * 100) / 100,
      avgWin: Math.round(avgWin * 100) / 100,
      avgLoss: Math.round(avgLoss * 100) / 100,
      expectancy: Math.round(expectancy * 100) / 100,
      tradeSetup: {
        entry: 'Enter at RTH open IF gap holds',
        stop: '-2% from entry',
        target: '+5% or prior resistance',
        expectedHoldTime: '2-4 hours'
      }
    };
  } catch (error) {
    console.error('Error detecting FDA pattern:', error);
    return null;
  }
}

/**
 * Detect Earnings Beat Fade pattern
 */
async function detectEarningsFadePattern(lookbackDays, minOccurrences) {
  try {
    const query = `
      WITH pattern_matches AS (
        SELECT 
          symbol,
          trade_date,
          first_cross_session,
          max_abs_pct_post,
          max_abs_pct_rth,
          opt_notional_bull,
          opt_notional_bear,
          daily_pct_change,
          news_earnings
        FROM (
          SELECT * FROM public.intraday_option_factors
          WHERE trade_date >= CURRENT_DATE - INTERVAL '${lookbackDays} days'
        ) factors
        WHERE news_earnings = 1
          AND first_cross_session = 'POST'
          AND max_abs_pct_post > max_abs_pct_rth
          AND opt_notional_bear > COALESCE(opt_notional_bull, 1)
      ),
      outcomes AS (
        SELECT 
          pm.*,
          CASE 
            WHEN pm.daily_pct_change <= -3 THEN 'WIN'
            WHEN pm.daily_pct_change >= 2 THEN 'LOSS'
            ELSE 'NEUTRAL'
          END AS outcome
        FROM pattern_matches pm
      )
      SELECT 
        COUNT(*) AS total_occurrences,
        SUM(CASE WHEN outcome = 'WIN' THEN 1 ELSE 0 END) AS wins,
        SUM(CASE WHEN outcome = 'LOSS' THEN 1 ELSE 0 END) AS losses,
        AVG(CASE WHEN outcome = 'WIN' THEN ABS(daily_pct_change) ELSE NULL END) AS avg_win,
        AVG(CASE WHEN outcome = 'LOSS' THEN daily_pct_change ELSE NULL END) AS avg_loss
      FROM outcomes
      WHERE outcome != 'NEUTRAL'
    `;
    
    const result = await rawQuery(query);
    
    if (!result || result.length === 0 || result[0].total_occurrences < minOccurrences) {
      return null;
    }
    
    const row = result[0];
    const total = parseInt(row.total_occurrences) || 0;
    const wins = parseInt(row.wins) || 0;
    const losses = parseInt(row.losses) || 0;
    const winRate = total > 0 ? wins / total : 0;
    const avgWin = parseFloat(row.avg_win) || 0;
    const avgLoss = parseFloat(row.avg_loss) || 0;
    const expectancy = (winRate * avgWin) + ((1 - winRate) * avgLoss);
    
    return {
      name: 'Earnings Beat Fade',
      description: 'Earnings beat with post-market spike but bearish options = fade the gap',
      criteria: {
        news_earnings: 1,
        first_cross_session: 'POST',
        max_abs_pct_post: '> max_abs_pct_rth (spike after hours)',
        opt_notional_bear: '> bull (despite price up)'
      },
      totalOccurrences: total,
      wins,
      losses,
      winRate: Math.round(winRate * 100) / 100,
      avgWin: Math.round(avgWin * 100) / 100,
      avgLoss: Math.round(avgLoss * 100) / 100,
      expectancy: Math.round(expectancy * 100) / 100,
      tradeSetup: {
        entry: 'Enter SHORT if gap opens but fades below VWAP in first 15min',
        stop: '+3% from entry',
        target: '-5% or prior day close',
        expectedHoldTime: '2-4 hours'
      }
    };
  } catch (error) {
    console.error('Error detecting earnings fade pattern:', error);
    return null;
  }
}

/**
 * Detect Gap Continuation pattern
 */
async function detectGapContinuationPattern(lookbackDays, minOccurrences) {
  // Simplified pattern detection
  // Real implementation would query actual data
  return null; // Placeholder
}

/**
 * Detect Options Flow Pre-Positioning pattern
 */
async function detectPrePositioningPattern(lookbackDays, minOccurrences) {
  try {
    // This would require tracking 3-day rolling options notional
    // Simplified version for now
    const query = `
      WITH daily_flow AS (
        SELECT 
          symbol,
          trade_date,
          opt_notional_bull,
          opt_notional_bear,
          LAG(opt_notional_bull) OVER (PARTITION BY symbol ORDER BY trade_date) AS prev_bull,
          LAG(opt_notional_bull, 2) OVER (PARTITION BY symbol ORDER BY trade_date) AS prev2_bull
        FROM (
          SELECT * FROM public.intraday_option_factors
          WHERE trade_date >= CURRENT_DATE - INTERVAL '${lookbackDays} days'
        ) factors
      ),
      surging AS (
        SELECT *
        FROM daily_flow
        WHERE opt_notional_bull > 2 * COALESCE(prev_bull, 0)
          AND prev_bull > 2 * COALESCE(prev2_bull, 0)
          AND opt_notional_bull > 10000000
      )
      SELECT 
        COUNT(*) AS total_occurrences,
        AVG(opt_notional_bull) AS avg_flow
      FROM surging
    `;
    
    const result = await rawQuery(query);
    
    if (!result || result.length === 0 || result[0].total_occurrences < minOccurrences) {
      return null;
    }
    
    return {
      name: 'Options Flow Pre-Positioning',
      description: 'Exponential growth in options flow 1-3 days before major events',
      criteria: {
        flow_growth: 'Today > 2x yesterday, yesterday > 2x day before',
        min_notional: '> $10M'
      },
      totalOccurrences: parseInt(result[0].total_occurrences) || 0,
      signal: 'Institutions loading up BEFORE announcement = bullish bias',
      tradeSetup: {
        entry: 'Monitor for entry on announcement day',
        stop: 'Based on event outcome',
        target: 'Follow institutional flow direction',
        expectedHoldTime: 'Event-driven'
      }
    };
  } catch (error) {
    console.error('Error detecting pre-positioning pattern:', error);
    return null;
  }
}

/**
 * Check if current ticker matches a playbook pattern
 * @param {string} symbol - Ticker symbol
 * @param {Array} playbooks - Array of playbook patterns
 * @returns {Object|null} Matching playbook or null
 */
export async function matchPlaybook(symbol, playbooks) {
  // This would check current ticker data against playbook criteria
  // Simplified version for now
  return null;
}

/**
 * Format playbook for display
 */
export function formatPlaybook(playbook) {
  if (!playbook) return null;
  
  return {
    name: playbook.name,
    winRate: `${Math.round(playbook.winRate * 100)}%`,
    occurrences: playbook.totalOccurrences,
    expectancy: `${playbook.expectancy > 0 ? '+' : ''}${playbook.expectancy.toFixed(2)}%`,
    setup: playbook.tradeSetup,
    full: playbook
  };
}

