/**
 * Convergence Detector
 * Detects when 3+ institutional signals fire within 10-minute window
 * Signals: Dark/Block, Options Flow, 52W High, ORB, Stealth Dark, Shock Tape
 */

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

/**
 * Detect convergence events (3+ signals within time window)
 * @param {number} lookbackMinutes - Time window to check (default 10)
 * @returns {Promise<Array>} Array of convergence events
 */
export async function detectConvergence(lookbackMinutes = 10) {
  const now = new Date();
  const signals = await getAllRecentSignals(lookbackMinutes);
  
  // Group by symbol
  const symbolMap = {};
  signals.forEach(signal => {
    const symbol = signal.symbol?.toUpperCase() || signal.ticker?.toUpperCase();
    if (!symbol) return;
    
    if (!symbolMap[symbol]) {
      symbolMap[symbol] = [];
    }
    symbolMap[symbol].push(signal);
  });
  
  const convergences = [];
  
  for (const [symbol, symbolSignals] of Object.entries(symbolMap)) {
    // Check if 3+ DIFFERENT signal types within 10min window
    const uniqueTypes = new Set(symbolSignals.map(s => s.type));
    
    if (uniqueTypes.size >= 3) {
      // This is a convergence event
      const timestamps = symbolSignals
        .map(s => s.timestamp ? new Date(s.timestamp).getTime() : 0)
        .filter(t => t > 0);
      
      if (timestamps.length === 0) continue;
      
      const firstSignal = Math.min(...timestamps);
      const lastSignal = Math.max(...timestamps);
      const timeWindow = Math.round((lastSignal - firstSignal) / 60000); // minutes
      
      const convergence = {
        symbol,
        signalCount: uniqueTypes.size,
        signals: Array.from(uniqueTypes),
        timestamps: symbolSignals.map(s => s.timestamp),
        firstSignal: new Date(firstSignal).toISOString(),
        lastSignal: new Date(lastSignal).toISOString(),
        timeWindow,
        totalNotional: symbolSignals.reduce((sum, s) => sum + (parseFloat(s.notional) || 0), 0),
        rocketScore: await getRocketScore(symbol),
        currentPrice: await getCurrentPrice(symbol),
        reasoning: generateConvergenceReasoning(symbolSignals)
      };
      
      convergences.push(convergence);
    }
  }
  
  // Sort by signal count (most signals first)
  return convergences.sort((a, b) => b.signalCount - a.signalCount);
}

/**
 * Get all recent signals from various sources
 */
async function getAllRecentSignals(lookbackMinutes) {
  const signals = [];
  
  // NOTE: Disabled queries for alertstream_monthly and AlertStream_monthly tables
  // as they don't have the latest data. Only using options_flow_enriched.
  
  // try {
  //   // 1. Dark Pool / Block Clusters
  //   const darkPoolQuery = `
  //     SELECT 
  //       UPPER(COALESCE(symbol, "Symbol", "Ticker")) as symbol,
  //       'DARK_POOL_CLUSTER' as type,
  //       SUM(COALESCE(notional::numeric, "Notional"::numeric, 0)) as notional,
  //       MAX(COALESCE(
  //         CASE 
  //           WHEN alert_time_txt ~* '(AM|PM)\\s*$'
  //             THEN to_timestamp(COALESCE(alert_date, "AlertDate", "date", "Date") || ' ' || alert_time_txt,
  //                             'YYYY-MM-DD HH12:MI:SS AM')::timestamp
  //           ELSE to_timestamp(COALESCE(alert_date, "AlertDate", "date", "Date") || ' ' || alert_time_txt,
  //                           'YYYY-MM-DD HH24:MI:SS')::timestamp
  //         END,
  //         COALESCE("timestamp"::timestamp, timestamp::timestamp, NOW())
  //       )) as timestamp
  //     FROM (
  //       SELECT symbol, NULL as ticker, symbol as "Symbol", NULL as "Ticker", 
  //              notional::numeric, NULL::numeric as "Notional",
  //              alert_date::text as alert_date, NULL::text as "AlertDate", alert_date::text as "date", NULL::text as "Date",
  //              alert_time_txt, NULL as "timestamp", NULL::timestamp as timestamp,
  //              alert_type as type, NULL as "Type", NULL as "AlertType", alert_type
  //       FROM public.alertstream_monthly
  //       WHERE alert_type IN ('DarkPool', 'Block')
  //       UNION ALL
  //       SELECT "Symbol" as symbol, "Ticker" as ticker, "Symbol", "Ticker",
  //              COALESCE("Notional"::numeric, 0) as notional, "Notional"::numeric,
  //              COALESCE("date"::text, "AlertDate"::text) as alert_date, "AlertDate"::text, "date"::text, "Date"::text,
  //              "Timestamp" as alert_time_txt, "timestamp", "timestamp"::timestamp as timestamp,
  //              "Type" as type, "Type", "AlertType", "Type" as alert_type
  //       FROM public."AlertStream_monthly"
  //       WHERE "Type" IN ('DarkPool', 'Block')
  //     ) alerts
  //     WHERE COALESCE(type, "Type", "AlertType", alert_type) IN ('DarkPool', 'Block')
  //       AND COALESCE(
  //         CASE 
  //           WHEN alert_time_txt ~* '(AM|PM)\\s*$'
  //             THEN to_timestamp(COALESCE(alert_date, "AlertDate", "date", "Date") || ' ' || alert_time_txt,
  //                             'YYYY-MM-DD HH12:MI:SS AM')::timestamp
  //           ELSE to_timestamp(COALESCE(alert_date, "AlertDate", "date", "Date") || ' ' || alert_time_txt,
  //                           'YYYY-MM-DD HH24:MI:SS')::timestamp
  //         END,
  //         COALESCE("timestamp"::timestamp, timestamp::timestamp, NOW())
  //       ) >= NOW() - INTERVAL '${lookbackMinutes} minutes'
  //       AND COALESCE(notional::numeric, "Notional"::numeric, 0) >= 1000000
  //     GROUP BY UPPER(COALESCE(symbol, "Symbol", "Ticker"))
  //     HAVING SUM(COALESCE(notional::numeric, "Notional"::numeric, 0)) >= 5000000
  //   `;
  //   const darkPools = await rawQuery(darkPoolQuery);
  //   signals.push(...darkPools.map(r => ({
  //     symbol: r.symbol,
  //     type: r.type,
  //     notional: r.notional,
  //     timestamp: r.timestamp
  //   })));
  // } catch (error) {
  //   console.error('Error fetching dark pool signals:', error);
  // }
  
  try {
    // 2. Options Flow (big premium) - using OptionsFlow_monthly table
    const optionsQuery = `
      SELECT 
        UPPER(TRIM("Symbol")) as symbol,
        'OPTIONS_FLOW' as type,
        SUM(NULLIF(REGEXP_REPLACE("Premium"::text, '[\\s$,]', '', 'g'),'')::numeric) as notional,
        MAX(("CreatedDate" || ' ' || COALESCE("CreatedTime", '00:00:00'))::timestamp) as timestamp
      FROM public."OptionsFlow_monthly"
      WHERE ("CreatedDate" || ' ' || COALESCE("CreatedTime", '00:00:00'))::timestamp >= NOW() - INTERVAL '${lookbackMinutes} minutes'
        AND NULLIF(REGEXP_REPLACE("Premium"::text, '[\\s$,]', '', 'g'),'')::numeric >= 500000
      GROUP BY UPPER(TRIM("Symbol"))
      HAVING SUM(NULLIF(REGEXP_REPLACE("Premium"::text, '[\\s$,]', '', 'g'),'')::numeric) >= 2000000
    `;
    const options = await rawQuery(optionsQuery);
    signals.push(...options.map(r => ({
      symbol: r.symbol,
      type: r.type,
      notional: r.notional,
      timestamp: r.timestamp
    })));
  } catch (error) {
    console.error('Error fetching options flow signals:', error);
  }
  
  // try {
  //   // 3. 52-Week Highs
  //   const highsQuery = `
  //     SELECT 
  //       UPPER(COALESCE(symbol, "Symbol", "Ticker")) as symbol,
  //       'FIFTY_TWO_WEEK_HIGH' as type,
  //       0 as notional,
  //       MAX(COALESCE(
  //         CASE 
  //           WHEN alert_time_txt ~* '(AM|PM)\\s*$'
  //             THEN to_timestamp(COALESCE(alert_date, "AlertDate", "date", "Date") || ' ' || alert_time_txt,
  //                             'YYYY-MM-DD HH12:MI:SS AM')::timestamp
  //           ELSE to_timestamp(COALESCE(alert_date, "AlertDate", "date", "Date") || ' ' || alert_time_txt,
  //                           'YYYY-MM-DD HH24:MI:SS')::timestamp
  //         END,
  //         COALESCE("timestamp"::timestamp, timestamp::timestamp, NOW())
  //       )) as timestamp
  //     FROM (
  //       SELECT symbol, NULL as ticker, symbol as "Symbol", NULL as "Ticker", 
  //              alert_date::text as alert_date, NULL::text as "AlertDate", alert_date::text as "date", NULL::text as "Date",
  //              alert_time_txt, NULL as "timestamp", NULL::timestamp as timestamp,
  //              alert_type as type, NULL as "Type", NULL as "AlertType", alert_type
  //       FROM public.alertstream_monthly
  //       WHERE alert_type = 'AnnualHigh'
  //       UNION ALL
  //       SELECT "Symbol" as symbol, "Ticker" as ticker, "Symbol", "Ticker",
  //              COALESCE("date"::text, "AlertDate"::text) as alert_date, "AlertDate"::text, "date"::text, "Date"::text,
  //              "Timestamp" as alert_time_txt, "timestamp", "timestamp"::timestamp as timestamp,
  //              "Type" as type, "Type", "AlertType", "Type" as alert_type
  //       FROM public."AlertStream_monthly"
  //       WHERE "Type" = 'AnnualHigh'
  //     ) alerts
  //     WHERE COALESCE(type, "Type", "AlertType", alert_type) = 'AnnualHigh'
  //       AND COALESCE(
  //         CASE 
  //           WHEN alert_time_txt ~* '(AM|PM)\\s*$'
  //             THEN to_timestamp(COALESCE(alert_date, "AlertDate", "date", "Date") || ' ' || alert_time_txt,
  //                             'YYYY-MM-DD HH12:MI:SS AM')::timestamp
  //           ELSE to_timestamp(COALESCE(alert_date, "AlertDate", "date", "Date") || ' ' || alert_time_txt,
  //                           'YYYY-MM-DD HH24:MI:SS')::timestamp
  //         END,
  //         COALESCE("timestamp"::timestamp, timestamp::timestamp, NOW())
  //       ) >= NOW() - INTERVAL '${lookbackMinutes} minutes'
  //     GROUP BY UPPER(COALESCE(symbol, "Symbol", "Ticker"))
  //   `;
  //   const highs = await rawQuery(highsQuery);
  //   signals.push(...highs.map(r => ({
  //     symbol: r.symbol,
  //     type: r.type,
  //     notional: 0,
  //     timestamp: r.timestamp
  //   })));
  // } catch (error) {
  //   console.error('Error fetching 52W high signals:', error);
  // }
  
  // try {
  //   // 4. ORB (Opening Range Breakouts)
  //   const orbQuery = `
  //     SELECT 
  //       UPPER(COALESCE(symbol, "Symbol", "Ticker")) as symbol,
  //       'ORB_BREAKOUT' as type,
  //       COALESCE(notional::numeric, "Notional"::numeric, 0) as notional,
  //       MAX(COALESCE(
  //         CASE 
  //           WHEN alert_time_txt ~* '(AM|PM)\\s*$'
  //             THEN to_timestamp(COALESCE(alert_date, "AlertDate", "date", "Date") || ' ' || alert_time_txt,
  //                             'YYYY-MM-DD HH12:MI:SS AM')::timestamp
  //           ELSE to_timestamp(COALESCE(alert_date, "AlertDate", "date", "Date") || ' ' || alert_time_txt,
  //                           'YYYY-MM-DD HH24:MI:SS')::timestamp
  //         END,
  //         COALESCE("timestamp"::timestamp, timestamp::timestamp, NOW())
  //       )) as timestamp
  //     FROM (
  //       SELECT symbol, NULL as ticker, symbol as "Symbol", NULL as "Ticker", 
  //              notional::numeric, NULL::numeric as "Notional",
  //              alert_date::text as alert_date, NULL::text as "AlertDate", alert_date::text as "date", NULL::text as "Date",
  //              alert_time_txt, NULL as "timestamp", NULL::timestamp as timestamp,
  //              alert_type as type, NULL as "Type", NULL as "AlertType", alert_type,
  //              pct_of_avg30, NULL::numeric as "Pct_of_Avg30", NULL::numeric as "Pct_of_Avg30Day", pct_of_avg30 as pct_of_avg30day
  //       FROM public.alertstream_monthly
  //       WHERE alert_type = 'Orb'
  //       UNION ALL
  //       SELECT "Symbol" as symbol, "Ticker" as ticker, "Symbol", "Ticker",
  //              COALESCE("Notional"::numeric, 0) as notional, "Notional"::numeric,
  //              COALESCE("date"::text, "AlertDate"::text) as alert_date, "AlertDate"::text, "date"::text, "Date"::text,
  //              "Timestamp" as alert_time_txt, "timestamp", "timestamp"::timestamp as timestamp,
  //              "Type" as type, "Type", "AlertType", "Type" as alert_type,
  //              "Pct_of_Avg30"::numeric as pct_of_avg30, "Pct_of_Avg30"::numeric, "Pct_of_Avg30Day"::numeric, "Pct_of_Avg30Day"::numeric as pct_of_avg30day
  //       FROM public."AlertStream_monthly"
  //       WHERE "Type" = 'Orb'
  //     ) alerts
  //     WHERE COALESCE(type, "Type", "AlertType", alert_type) = 'Orb'
  //       AND COALESCE(
  //         CASE 
  //           WHEN alert_time_txt ~* '(AM|PM)\\s*$'
  //             THEN to_timestamp(COALESCE(alert_date, "AlertDate", "date", "Date") || ' ' || alert_time_txt,
  //                             'YYYY-MM-DD HH12:MI:SS AM')::timestamp
  //           ELSE to_timestamp(COALESCE(alert_date, "AlertDate", "date", "Date") || ' ' || alert_time_txt,
  //                           'YYYY-MM-DD HH24:MI:SS')::timestamp
  //         END,
  //         COALESCE("timestamp"::timestamp, timestamp::timestamp, NOW())
  //       ) >= NOW() - INTERVAL '${lookbackMinutes} minutes'
  //       AND COALESCE(pct_of_avg30::numeric, "Pct_of_Avg30"::numeric, "Pct_of_Avg30Day"::numeric, pct_of_avg30day::numeric, 0) >= 150
  //     GROUP BY UPPER(COALESCE(symbol, "Symbol", "Ticker")), 
  //              COALESCE(notional::numeric, "Notional"::numeric, 0)
  //   `;
  //   const orbs = await rawQuery(orbQuery);
  //   signals.push(...orbs.map(r => ({
  //     symbol: r.symbol,
  //     type: r.type,
  //     notional: r.notional,
  //     timestamp: r.timestamp
  //   })));
  // } catch (error) {
  //   console.error('Error fetching ORB signals:', error);
  // }
  
  // try {
  //   // 5. Price Spikes (Shock Tape)
  //   const spikesQuery = `
  //     SELECT 
  //       UPPER(COALESCE(symbol, "Symbol", "Ticker")) as symbol,
  //       'SHOCK_TAPE' as type,
  //       0 as notional,
  //       MAX(COALESCE(
  //         CASE 
  //           WHEN alert_time_txt ~* '(AM|PM)\\s*$'
  //             THEN to_timestamp(COALESCE(alert_date, "AlertDate", "date", "Date") || ' ' || alert_time_txt,
  //                             'YYYY-MM-DD HH12:MI:SS AM')::timestamp
  //           ELSE to_timestamp(COALESCE(alert_date, "AlertDate", "date", "Date") || ' ' || alert_time_txt,
  //                           'YYYY-MM-DD HH24:MI:SS')::timestamp
  //         END,
  //         COALESCE("timestamp"::timestamp, timestamp::timestamp, NOW())
  //       )) as timestamp
  //     FROM (
  //       SELECT symbol, NULL as ticker, symbol as "Symbol", NULL as "Ticker", 
  //              alert_date::text as alert_date, NULL::text as "AlertDate", alert_date::text as "date", NULL::text as "Date",
  //              alert_time_txt, NULL as "timestamp", NULL::timestamp as timestamp,
  //              alert_type as type, NULL as "Type", NULL as "AlertType", alert_type
  //       FROM public.alertstream_monthly
  //       WHERE alert_type IN ('PriceSpike', 'RapidDecline')
  //       UNION ALL
  //       SELECT "Symbol" as symbol, "Ticker" as ticker, "Symbol", "Ticker",
  //              COALESCE("date"::text, "AlertDate"::text) as alert_date, "AlertDate"::text, "date"::text, "Date"::text,
  //              "Timestamp" as alert_time_txt, "timestamp", "timestamp"::timestamp as timestamp,
  //              "Type" as type, "Type", "AlertType", "Type" as alert_type
  //       FROM public."AlertStream_monthly"
  //       WHERE "Type" IN ('PriceSpike', 'RapidDecline')
  //     ) alerts
  //     WHERE COALESCE(type, "Type", "AlertType", alert_type) IN ('PriceSpike', 'RapidDecline')
  //       AND COALESCE(
  //         CASE 
  //           WHEN alert_time_txt ~* '(AM|PM)\\s*$'
  //             THEN to_timestamp(COALESCE(alert_date, "AlertDate", "date", "Date") || ' ' || alert_time_txt,
  //                             'YYYY-MM-DD HH12:MI:SS AM')::timestamp
  //           ELSE to_timestamp(COALESCE(alert_date, "AlertDate", "date", "Date") || ' ' || alert_time_txt,
  //                           'YYYY-MM-DD HH24:MI:SS')::timestamp
  //         END,
  //         COALESCE("timestamp"::timestamp, timestamp::timestamp, NOW())
  //       ) >= NOW() - INTERVAL '${lookbackMinutes} minutes'
  //     GROUP BY UPPER(COALESCE(symbol, "Symbol", "Ticker"))
  //   `;
  //   const spikes = await rawQuery(spikesQuery);
  //   signals.push(...spikes.map(r => ({
  //     symbol: r.symbol,
  //     type: r.type,
  //     notional: 0,
  //     timestamp: r.timestamp
  //   })));
  // } catch (error) {
  //   console.error('Error fetching shock tape signals:', error);
  // }
  
  // try {
  //   // 6. Stealth Dark (high notional, low rVol)
  //   const stealthQuery = `
  //     SELECT 
  //       UPPER(COALESCE(symbol, "Symbol", "Ticker")) as symbol,
  //       'STEALTH_DARK' as type,
  //       COALESCE(notional::numeric, "Notional"::numeric, 0) as notional,
  //       MAX(COALESCE(
  //         CASE 
  //           WHEN alert_time_txt ~* '(AM|PM)\\s*$'
  //             THEN to_timestamp(COALESCE(alert_date, "AlertDate", "date", "Date") || ' ' || alert_time_txt,
  //                             'YYYY-MM-DD HH12:MI:SS AM')::timestamp
  //           ELSE to_timestamp(COALESCE(alert_date, "AlertDate", "date", "Date") || ' ' || alert_time_txt,
  //                           'YYYY-MM-DD HH24:MI:SS')::timestamp
  //         END,
  //         COALESCE("timestamp"::timestamp, timestamp::timestamp, NOW())
  //       )) as timestamp
  //     FROM (
  //       SELECT symbol, NULL as ticker, symbol as "Symbol", NULL as "Ticker", 
  //              notional::numeric, NULL::numeric as "Notional",
  //              alert_date::text as alert_date, NULL::text as "AlertDate", alert_date::text as "date", NULL::text as "Date",
  //              alert_time_txt, NULL as "timestamp", NULL::timestamp as timestamp,
  //              alert_type as type, NULL as "Type", NULL as "AlertType", alert_type,
  //              pct_of_avg30, NULL::numeric as "Pct_of_Avg30", NULL::numeric as "Pct_of_Avg30Day", pct_of_avg30 as pct_of_avg30day
  //       FROM public.alertstream_monthly
  //       WHERE alert_type = 'DarkPool'
  //       UNION ALL
  //       SELECT "Symbol" as symbol, "Ticker" as ticker, "Symbol", "Ticker",
  //              COALESCE("Notional"::numeric, 0) as notional, "Notional"::numeric,
  //              COALESCE("date"::text, "AlertDate"::text) as alert_date, "AlertDate"::text, "date"::text, "Date"::text,
  //              "Timestamp" as alert_time_txt, "timestamp", "timestamp"::timestamp as timestamp,
  //              "Type" as type, "Type", "AlertType", "Type" as alert_type,
  //              "Pct_of_Avg30"::numeric as pct_of_avg30, "Pct_of_Avg30"::numeric, "Pct_of_Avg30Day"::numeric, "Pct_of_Avg30Day"::numeric as pct_of_avg30day
  //       FROM public."AlertStream_monthly"
  //       WHERE "Type" = 'DarkPool'
  //     ) alerts
  //     WHERE COALESCE(type, "Type", "AlertType", alert_type) = 'DarkPool'
  //       AND COALESCE(
  //         CASE 
  //           WHEN alert_time_txt ~* '(AM|PM)\\s*$'
  //             THEN to_timestamp(COALESCE(alert_date, "AlertDate", "date", "Date") || ' ' || alert_time_txt,
  //                             'YYYY-MM-DD HH12:MI:SS AM')::timestamp
  //           ELSE to_timestamp(COALESCE(alert_date, "AlertDate", "date", "Date") || ' ' || alert_time_txt,
  //                           'YYYY-MM-DD HH24:MI:SS')::timestamp
  //         END,
  //         COALESCE("timestamp"::timestamp, timestamp::timestamp, NOW())
  //       ) >= NOW() - INTERVAL '${lookbackMinutes} minutes'
  //       AND COALESCE(notional::numeric, "Notional"::numeric, 0) >= 3000000
  //       AND COALESCE(pct_of_avg30::numeric, "Pct_of_Avg30"::numeric, "Pct_of_Avg30Day"::numeric, pct_of_avg30day::numeric, 200) < 100
  //     GROUP BY UPPER(COALESCE(symbol, "Symbol", "Ticker")), 
  //              COALESCE(notional::numeric, "Notional"::numeric, 0)
  //   `;
  //   const stealth = await rawQuery(stealthQuery);
  //   signals.push(...stealth.map(r => ({
  //     symbol: r.symbol,
  //     type: r.type,
  //     notional: r.notional,
  //     timestamp: r.timestamp
  //   })));
  // } catch (error) {
  //   console.error('Error fetching stealth dark signals:', error);
  // }
  
  return signals;
}

/**
 * Generate human-readable reasoning for convergence
 */
function generateConvergenceReasoning(signals) {
  const typeLabels = {
    'DARK_POOL_CLUSTER': '🌑 Dark Pool Accumulation',
    'OPTIONS_FLOW': '📊 Heavy Options Activity',
    'FIFTY_TWO_WEEK_HIGH': '📈 52-Week High Breakout',
    'ORB_BREAKOUT': '🚀 Opening Range Breakout',
    'SHOCK_TAPE': '⚡ Price Spike Detected',
    'STEALTH_DARK': '🥷 Stealth Accumulation'
  };
  
  const reasons = signals.map(s => {
    const type = s.type || s.signalType;
    return typeLabels[type] || type;
  });
  
  // Remove duplicates and join
  return [...new Set(reasons)].join(' + ');
}

/**
 * Get rocket score for a symbol
 */
async function getRocketScore(symbol) {
  try {
    // Rocket score is calculated dynamically, not stored in OptionsFlow_monthly
    // Return 0 for now - can be enhanced later if needed
    return 0;
  } catch (error) {
    console.error(`Error fetching rocket score for ${symbol}:`, error);
    return 0;
  }
}

/**
 * Get current price for a symbol
 */
async function getCurrentPrice(symbol) {
  try {
    const query = `
      SELECT DISTINCT ON (UPPER(COALESCE(symbol, "Symbol", Ticker, ticker)))
        close AS price
      FROM prices_intraday_1m
      WHERE UPPER(COALESCE(symbol, "Symbol", Ticker, ticker)) = $1
        AND ts >= NOW() - INTERVAL '1 day'
      ORDER BY UPPER(COALESCE(symbol, "Symbol", Ticker, ticker)), ts DESC
      LIMIT 1
    `;
    const result = await rawQuery(query, [symbol.toUpperCase()]);
    return parseFloat(result[0]?.price || 0);
  } catch (error) {
    console.error(`Error fetching current price for ${symbol}:`, error);
    return 0;
  }
}

