/**
 * Trade Plan Generator
 * Auto-generates complete trade plans for every high-score signal
 * 
 * @param {Object} flowData - Enriched flow data with badges, scores, price context
 * @returns {Object} tradePlan - Complete trade plan
 */

export function generateTradePlan(flowData) {
  const plan = {
    symbol: flowData.symbol_norm || flowData.Symbol || 'UNKNOWN',
    signal: null,        // 'BUY', 'SELL', 'WAIT'
    confidence: 0,       // 0-100%
    readiness: 0,        // 0-100% readiness score for WAIT signals
    waitStatusMessage: null,  // Dynamic status message for WAIT signals
    
    entry: {
      primary: null,     // Primary entry price
      aggressive: null,  // Aggressive entry price
      reasoning: ''
    },
    
    stopLoss: {
      tight: null,       // -1% stop
      wide: null,        // -2% stop
      reasoning: ''
    },
    
    targets: {
      t1: { price: null, percentage: 50, gain: null },  // Take 50% at T1
      t2: { price: null, percentage: 30, gain: null },  // Take 30% at T2
      t3: { price: null, percentage: 20, gain: null }   // Runner 20% at T3
    },
    
    timeHorizon: {
      expected: '',      // 'minutes', 'hours', 'days'
      maxHold: '',       // 'EOD', '2 days', etc.
      style: ''          // 'SCALP', 'INTRADAY', 'SWING'
    },
    
    reasoning: {
      why: [],           // Array of reasons (e.g., "Dark pool cluster at $175")
      catalysts: [],     // Array of catalysts
      risks: []          // Array of risk factors
    },
    
    invalidation: {
      priceLevel: null,  // If breaks this level, exit
      conditions: []     // Array of invalidation conditions
    },
    
    riskReward: {
      risk: null,        // % risk
      reward: null,      // % reward
      ratio: null        // R:R ratio
    },
    
    historicalEdge: {
      similarSetups: 0,
      winRate: 0,
      avgWin: 0,
      avgLoss: 0,
      expectancy: 0
    }
  };
  
  // 1. DETERMINE SIGNAL (BUY/SELL/WAIT)
  plan.signal = determineSignal(flowData);
  plan.confidence = calculateConfidence(flowData);
  
  // Add reasoning for WAIT signals
  if (plan.signal === 'WAIT') {
    const waitReasons = getWaitReasons(flowData);
    plan.reasoning.why = [...(plan.reasoning.why || []), ...waitReasons];
  }
  
  // 2. GENERATE ENTRY STRATEGY
  plan.entry = generateEntryStrategy(flowData, plan.signal);
  
  // 3. CALCULATE STOP LOSS (use entry price if available, otherwise current price for WAIT signals)
  plan.stopLoss = calculateStopLoss(flowData, plan.entry.primary);
  
  // 4. CALCULATE TARGETS (use entry price if available, otherwise current price for WAIT signals)
  plan.targets = calculateTargets(flowData, plan.entry.primary, plan.signal);
  
  // 5. DETERMINE TIME HORIZON
  plan.timeHorizon = determineTimeHorizon(flowData);
  
  // 6. BUILD REASONING
  plan.reasoning = buildReasoning(flowData);
  
  // 7. SET INVALIDATION CONDITIONS
  plan.invalidation = setInvalidationConditions(flowData, plan.stopLoss.wide);
  
  // 8. CALCULATE RISK/REWARD
  plan.riskReward = calculateRiskReward(
    plan.entry.primary,
    plan.stopLoss.tight,
    plan.targets.t1.price
  );
  
  // 9. CALCULATE READINESS (for WAIT signals)
  plan.readiness = calculateReadiness(plan);
  
  // 10. GENERATE WAIT STATUS MESSAGE (for WAIT signals)
  if (plan.signal === 'WAIT') {
    plan.waitStatusMessage = generateWaitStatusMessage(plan, flowData);
  }
  
  // 11. FETCH HISTORICAL EDGE (if backtester exists)
  // plan.historicalEdge = await getHistoricalEdge(flowData);
  
  return plan;
}

// ===== HELPER FUNCTIONS =====

function determineSignal(flow) {
  const badges = flow.badgesRaw || flow.badges || {};
  const hasBullRound = badges.round === '🟢';
  const hasBearRound = badges.round === '🔴';
  const more = badges.more || '';
  const hasDiamond = more.includes('💎');
  const hasStar = more.includes('⭐');
  const hasMoney = more.includes('💰');
  const hasFlash = badges.flash === '⚡';
  const tapeAligned = flow.tapeAligned || flow.tape_alignment === 1;
  const score = flow.rocketScore || flow.rocket_score || 0;
  
  // INSTITUTIONAL FOMO (Strong BUY)
  if (hasBullRound && hasDiamond && hasStar && hasMoney && hasFlash && score >= 5) {
    return 'BUY';
  }
  
  // INSTITUTIONAL DISTRIBUTION (Strong SELL)
  if (hasBearRound && hasDiamond && hasStar && hasMoney && score >= 5) {
    return 'SELL';
  }
  
  // BULLISH BUT LOWER CONVICTION
  if (hasBullRound && hasDiamond && tapeAligned && score >= 3) {
    return 'BUY';
  }
  
  // BEARISH BUT LOWER CONVICTION
  if (hasBearRound && hasDiamond && tapeAligned && score >= 3) {
    return 'SELL';
  }
  
  // TRAP WARNING (Flow bullish but price not confirming)
  if (hasBullRound && !tapeAligned) {
    return 'WAIT';
  }
  
  // DEFAULT: WAIT
  return 'WAIT';
}

function calculateConfidence(flow) {
  let confidence = 0;
  const badges = flow.badgesRaw || flow.badges || {};
  const score = flow.rocketScore || flow.rocket_score || 0;
  
  // Base confidence from score
  confidence += (score / 10) * 50;  // 0-50 points from score
  
  // Tape alignment bonus
  if (flow.tapeAligned || flow.tape_alignment === 1) confidence += 20;
  
  // Catalyst bonus
  if (flow.near_alert_type) confidence += 10;
  
  // Flow freshness bonus (recent flow = higher confidence)
  const lastFlowMinutes = flow.lastFlowMinutes || 0;
  if (lastFlowMinutes < 5) confidence += 10;
  else if (lastFlowMinutes < 15) confidence += 5;
  
  // Session bonus (RTH = higher confidence)
  if (flow.session_bucket === 'RTH') confidence += 10;
  
  return Math.min(Math.round(confidence), 100);
}

/**
 * Get reasons why signal is WAIT (what's missing)
 */
function getWaitReasons(flow) {
  const reasons = [];
  const badges = flow.badgesRaw || flow.badges || {};
  const hasBullRound = badges.round === '🟢';
  const hasBearRound = badges.round === '🔴';
  const tapeAligned = flow.tapeAligned || flow.tape_alignment === 1;
  const score = flow.rocketScore || flow.rocket_score || 0;
  const confidence = calculateConfidence(flow);
  
  // Most common: Flow bullish but price not confirming
  if (hasBullRound && !tapeAligned) {
    reasons.push('Price not confirming flow - potential trap');
  }
  
  // Low score
  if (score < 3) {
    reasons.push(`Low rocket score (${score.toFixed(1)}/10) - need stronger flow`);
  }
  
  // Low confidence
  if (confidence < 50) {
    reasons.push(`Low confidence (${confidence}%) - insufficient signals`);
  }
  
  // Missing tape alignment
  if (!tapeAligned && confidence < 60) {
    reasons.push('Price action not aligned with flow');
  }
  
  // Missing catalyst
  if (!flow.near_alert_type && confidence < 70) {
    reasons.push('No nearby catalyst detected');
  }
  
  // Stale flow
  const lastFlowMinutes = flow.lastFlowMinutes || 999;
  if (lastFlowMinutes > 30) {
    reasons.push(`Flow is stale (${lastFlowMinutes}min ago)`);
  }
  
  return reasons.length > 0 ? reasons : ['Insufficient conviction for trade'];
}

function generateEntryStrategy(flow, signal) {
  // PRIORITY: Use Yahoo Finance data (real-time) over database (stale)
  // Yahoo Finance data comes from flow.yahooPriceData or flow.stockPriceData
  const yahooData = flow.yahooPriceData || flow.stockPriceData;
  
  // Get current price from Yahoo Finance first, then fallback to database
  const currentPrice = yahooData?.currentPrice 
    || flow.spot_num 
    || flow.u_close 
    || flow.last_px 
    || flow.Price 
    || 0;
  
  if (!currentPrice || currentPrice === 0) {
    return {
      primary: null,
      aggressive: null,
      reasoning: 'Current price data unavailable',
      conditionalTriggers: []
    };
  }
  
  // Use Yahoo Finance data for today's prices
  const todayOpen = yahooData?.open || flow.rth_open || flow.rthOpen || currentPrice;
  const todayHigh = yahooData?.high || flow.u_high || currentPrice;
  const todayLow = yahooData?.low || flow.u_low || currentPrice;
  const previousClose = yahooData?.previousClose || flow.prior_close || flow.priorClose || currentPrice;
  
  // VWAP: prefer calculated from Yahoo Finance, fallback to database
  const vwap = flow.vwap_at_signal || flow.vwap_lb || flow.vwap;
  
  // Opening Range: Use Yahoo Finance volumeHistory to calculate OR high/low from today
  // OR is typically 8:30-9:00 AM, but we'll use today's open/high/low as proxy
  let orHigh = flow.or_high;
  let orLow = flow.or_low;
  
  // If we have Yahoo Finance data, use today's high/low as OR levels (more accurate)
  if (yahooData) {
    // Use today's high as OR high if it's reasonable
    if (todayHigh && todayHigh > todayOpen) {
      orHigh = todayHigh;
    }
    // Use today's low as OR low if it's reasonable
    if (todayLow && todayLow < todayOpen) {
      orLow = todayLow;
    }
  }
  
  // Validate OR levels are reasonable (within 10% of current price)
  if (orHigh && Math.abs(orHigh - currentPrice) / currentPrice > 0.10) {
    orHigh = null; // Stale data, ignore it
  }
  if (orLow && Math.abs(orLow - currentPrice) / currentPrice > 0.10) {
    orLow = null; // Stale data, ignore it
  }
  orHigh = orHigh || (currentPrice * 1.01);
  orLow = orLow || (currentPrice * 0.99);
  
  // Prior High: Use Yahoo Finance volumeHistory to get previous day's high
  let priorHigh = flow.prior_high || flow.priorHigh;
  
  // If we have Yahoo Finance volumeHistory, get prior day's high from there
  if (yahooData?.volumeHistory && yahooData.volumeHistory.length > 0) {
    // volumeHistory is sorted by date descending (most recent first)
    // Get yesterday's high (index 1, since index 0 is today)
    if (yahooData.volumeHistory.length > 1) {
      const yesterday = yahooData.volumeHistory[1];
      if (yesterday.high && yesterday.high > currentPrice) {
        priorHigh = yesterday.high;
      }
    }
  }
  
  // Validate priorHigh is reasonable (within 10% above current price)
  if (priorHigh && (priorHigh < currentPrice || (priorHigh - currentPrice) / currentPrice > 0.10)) {
    priorHigh = null; // Stale or unreasonable data
  }
  priorHigh = priorHigh || (currentPrice * 1.02);
  
  const tapeAligned = flow.tapeAligned || flow.tape_alignment === 1;
  const flowTrend = flow.flowTrendRaw || flow.flowTrend?.full;
  const lastFlowMinutes = flow.lastFlowMinutes || 999;
  const premium = flow.premium_num || 0;
  
  if (signal === 'BUY') {
    // Generate price-based triggers
    const triggers = generatePriceTriggers(flow, 'BUY', currentPrice, vwap, todayOpen, previousClose, orHigh, priorHigh);
    
    return {
      primary: vwap ? vwap.toFixed(2) : currentPrice.toFixed(2),
      aggressive: orHigh ? orHigh.toFixed(2) : (currentPrice * 1.005).toFixed(2),
      reasoning: vwap 
        ? `Wait for pullback to VWAP ($${vwap.toFixed(2)}) for better entry`
        : `Enter at current price or on breakout above opening range high`,
      conditionalTriggers: triggers
    };
  } else if (signal === 'SELL') {
    const triggers = generatePriceTriggers(flow, 'SELL', currentPrice, vwap, todayOpen, previousClose, orLow, priorHigh);
    
    return {
      primary: vwap ? vwap.toFixed(2) : currentPrice.toFixed(2),
      aggressive: orLow ? orLow.toFixed(2) : (currentPrice * 0.995).toFixed(2),
      reasoning: vwap
        ? `Wait for rally to VWAP ($${vwap.toFixed(2)}) to short`
        : `Short at current price or on breakdown below opening range low`,
      conditionalTriggers: triggers
    };
  } else {
    // WAIT signal - generate conditional entry triggers
    const conditionalTriggers = generateConditionalEntryTriggers(flow, currentPrice, vwap, todayOpen, previousClose, orHigh, orLow, priorHigh, tapeAligned, flowTrend, lastFlowMinutes, premium);
    
    return {
      primary: null,
      aggressive: null,
      reasoning: 'Entry activates when conditions below are met',
      conditionalTriggers: conditionalTriggers
    };
  }
}

/**
 * Generate conditional entry triggers for WAIT signals
 */
function generateConditionalEntryTriggers(flow, currentPrice, vwap, todayOpen, priorClose, orHigh, orLow, priorHigh, tapeAligned, flowTrend, lastFlowMinutes, premium) {
  const triggers = [];
  const badges = flow.badgesRaw || flow.badges || {};
  const hasBullRound = badges.round === '🟢';
  const hasBearRound = badges.round === '🔴';
  const direction = hasBullRound ? 'BUY' : hasBearRound ? 'SHORT' : null;
  
  if (!direction) return triggers;
  
  // Price-based triggers - validate prices are reasonable relative to CURRENT price
  // VWAP: only if within 5% of current price
  if (vwap && currentPrice > 0) {
    const vwapDiff = Math.abs(vwap - currentPrice) / currentPrice;
    if (vwapDiff <= 0.05) {
      if (currentPrice < vwap) {
        triggers.push({
          type: 'VWAP_RECLAIM',
          condition: `Price reclaims VWAP ($${vwap.toFixed(2)}) and holds for 2 candles`,
          price: vwap.toFixed(2),
          priority: 'HIGH'
        });
      }
    }
  }
  
  // Prior high: only if it's above current price and within 10% above
  if (priorHigh && priorHigh > 0 && currentPrice > 0) {
    const pctDiff = (priorHigh - currentPrice) / currentPrice;
    if (pctDiff > 0 && pctDiff <= 0.10 && priorHigh > currentPrice) {
      triggers.push({
        type: 'PRIOR_HIGH_BREAK',
        condition: `Price breaks prior high ($${priorHigh.toFixed(2)})`,
        price: priorHigh.toFixed(2),
        priority: 'MEDIUM'
      });
    }
  }
  
  // OR high: only if it's above current price and within 5% above
  if (orHigh && orHigh > 0 && currentPrice > 0) {
    const pctDiff = (orHigh - currentPrice) / currentPrice;
    if (pctDiff > 0 && pctDiff <= 0.05 && orHigh > currentPrice) {
      triggers.push({
        type: 'ORB_BREAKOUT',
        condition: `Opening range breakout above $${orHigh.toFixed(2)}`,
        price: orHigh.toFixed(2),
        priority: 'MEDIUM'
      });
    }
  }
  
  // Flow-based triggers
  if (!tapeAligned) {
    triggers.push({
      type: 'TAPE_ALIGNMENT',
      condition: 'Tape alignment turns positive (price confirms flow direction)',
      price: null,
      priority: 'HIGH'
    });
  }
  
  if (flowTrend?.trend === 'DEAD' || lastFlowMinutes > 30) {
    triggers.push({
      type: 'FLOW_RESUMPTION',
      condition: `Flow resumes ≥ $${(premium >= 500000 ? (premium / 1000).toFixed(0) : 500)}K within 10 minutes`,
      price: null,
      priority: 'HIGH'
    });
  }
  
  // Range expansion
  if (currentPrice > 0 && todayOpen > 0) {
    const rangeSize = Math.abs(currentPrice - todayOpen) / todayOpen;
    if (rangeSize < 0.02) { // Less than 2% range
      triggers.push({
        type: 'RANGE_EXPANSION',
        condition: 'Price breaks out >2% from opening range',
        price: null,
        priority: 'MEDIUM'
      });
    }
  }
  
  return triggers;
}

/**
 * Generate price-based triggers for BUY/SELL signals
 */
function generatePriceTriggers(flow, direction, currentPrice, vwap, todayOpen, priorClose, orLevel, priorHigh) {
  const triggers = [];
  
  if (direction === 'BUY') {
    if (vwap && currentPrice < vwap) {
      triggers.push({
        type: 'VWAP_RECLAIM',
        condition: `VWAP reclaim trigger at $${vwap.toFixed(2)}`,
        price: vwap.toFixed(2)
      });
    }
    
    if (priorHigh && currentPrice < priorHigh) {
      triggers.push({
        type: 'PRIOR_HIGH_BREAK',
        condition: `Prior high break at $${priorHigh.toFixed(2)}`,
        price: priorHigh.toFixed(2)
      });
    }
    
    if (orLevel && currentPrice < orLevel) {
      triggers.push({
        type: 'ORB_BREAKOUT',
        condition: `Opening range breakout at $${orLevel.toFixed(2)}`,
        price: orLevel.toFixed(2)
      });
    }
  } else {
    if (vwap && currentPrice > vwap) {
      triggers.push({
        type: 'VWAP_REJECTION',
        condition: `VWAP rejection trigger at $${vwap.toFixed(2)}`,
        price: vwap.toFixed(2)
      });
    }
    
    if (orLevel && currentPrice > orLevel) {
      triggers.push({
        type: 'ORB_BREAKDOWN',
        condition: `Opening range breakdown at $${orLevel.toFixed(2)}`,
        price: orLevel.toFixed(2)
      });
    }
  }
  
  return triggers;
}

function calculateStopLoss(flow, entryPrice) {
  // PRIORITY: Use Yahoo Finance data (real-time) over database (stale)
  const yahooData = flow.yahooPriceData || flow.stockPriceData;
  
  // Get current price from Yahoo Finance first, then fallback to database
  const currentPrice = yahooData?.currentPrice 
    || flow.spot_num 
    || flow.u_close 
    || flow.last_px 
    || flow.Price 
    || 0;
  
  const referencePrice = entryPrice ? parseFloat(entryPrice) : currentPrice;
  
  if (!referencePrice || referencePrice === 0) {
    return { tight: null, wide: null, reasoning: 'No price data available' };
  }
  
  // Use Yahoo Finance data for today's prices
  const todayOpen = yahooData?.open || flow.rth_open || currentPrice;
  const todayLow = yahooData?.low || flow.u_low;
  const todayHigh = yahooData?.high || flow.u_high;
  
  // Opening Range: Use Yahoo Finance data if available
  let orLow = flow.or_low;
  let orHigh = flow.or_high;
  
  // If we have Yahoo Finance data, use today's low/high as OR levels
  if (yahooData) {
    if (todayLow && todayLow < todayOpen) {
      orLow = todayLow;
    }
    if (todayHigh && todayHigh > todayOpen) {
      orHigh = todayHigh;
    }
  }
  
  // Fallback to calculated values if not available
  orLow = orLow || (todayOpen ? (todayOpen * 0.99) : null);
  orHigh = orHigh || (todayOpen ? (todayOpen * 1.01) : null);
  
  const direction = flow.direction;
  const signal = flow.tradeSignal?.signal || flow.signal;
  
  let tight, wide, reasoning;
  
  if (direction === 'BULL' || signal === 'BUY') {
    tight = (referencePrice * 0.985).toFixed(2);  // -1.5% stop
    // Use OR low if it's reasonable (within 5% of current price), otherwise use percentage
    const wideStop = orLow && Math.abs(orLow - referencePrice) / referencePrice < 0.05 
      ? orLow.toFixed(2) 
      : (referencePrice * 0.975).toFixed(2);
    wide = wideStop;
    reasoning = `Tight stop at -1.5% for quick exit. Wide stop below opening range low or -2.5%.`;
  } else {
    tight = (referencePrice * 1.015).toFixed(2);  // +1.5% stop
    // Use OR high if it's reasonable (within 5% of current price), otherwise use percentage
    const wideStop = orHigh && Math.abs(orHigh - referencePrice) / referencePrice < 0.05 
      ? orHigh.toFixed(2) 
      : (referencePrice * 1.025).toFixed(2);
    wide = wideStop;
    reasoning = `Tight stop at +1.5% for quick exit. Wide stop above opening range high or +2.5%.`;
  }
  
  return { tight, wide, reasoning };
}

function calculateTargets(flow, entryPrice, signal) {
  // PRIORITY: Use Yahoo Finance data (real-time) over database (stale)
  const yahooData = flow.yahooPriceData || flow.stockPriceData;
  
  // Get current price from Yahoo Finance first, then fallback to database
  const currentPrice = yahooData?.currentPrice 
    || flow.spot_num 
    || flow.u_close 
    || flow.last_px 
    || flow.Price 
    || 0;
  
  const referencePrice = entryPrice ? parseFloat(entryPrice) : currentPrice;
  
  if (!referencePrice || referencePrice === 0) {
    return { t1: {}, t2: {}, t3: {} };
  }
  
  const strike = flow.strike_num || flow.Strike;
  const strikePrice = strike ? parseFloat(strike) : null;
  
  // Only use strike price if it's within reasonable range (not more than 20% away)
  const isStrikeReasonable = strikePrice && 
    Math.abs(strikePrice - referencePrice) / referencePrice <= 0.20;
  
  let t1Price, t2Price, t3Price;
  
  if (signal === 'BUY') {
    t1Price = (referencePrice * 1.015).toFixed(2);  // +1.5%
    t2Price = (referencePrice * 1.025).toFixed(2);  // +2.5%
    // Use strike only if it's reasonable, otherwise use percentage target
    if (isStrikeReasonable && strikePrice > referencePrice) {
      t3Price = strikePrice.toFixed(2);
    } else {
      t3Price = (referencePrice * 1.04).toFixed(2);  // +4% default
    }
  } else if (signal === 'SELL') {
    t1Price = (referencePrice * 0.985).toFixed(2);  // -1.5%
    t2Price = (referencePrice * 0.975).toFixed(2);  // -2.5%
    // Use strike only if it's reasonable, otherwise use percentage target
    if (isStrikeReasonable && strikePrice < referencePrice) {
      t3Price = strikePrice.toFixed(2);
    } else {
      t3Price = (referencePrice * 0.96).toFixed(2);  // -4% default
    }
  } else {
    // For WAIT signals, calculate based on direction from flow
    const direction = flow.direction;
    if (direction === 'BULL') {
      t1Price = (referencePrice * 1.015).toFixed(2);  // +1.5%
      t2Price = (referencePrice * 1.025).toFixed(2);  // +2.5%
      t3Price = isStrikeReasonable && strikePrice > referencePrice 
        ? strikePrice.toFixed(2) 
        : (referencePrice * 1.04).toFixed(2);
    } else {
      t1Price = (referencePrice * 0.985).toFixed(2);  // -1.5%
      t2Price = (referencePrice * 0.975).toFixed(2);  // -2.5%
      t3Price = isStrikeReasonable && strikePrice < referencePrice 
        ? strikePrice.toFixed(2) 
        : (referencePrice * 0.96).toFixed(2);
    }
  }
  
  const entry = parseFloat(referencePrice);
  
  return {
    t1: { 
      price: t1Price, 
      percentage: 50, 
      gain: ((parseFloat(t1Price) - entry) / entry * 100).toFixed(2) + '%'
    },
    t2: { 
      price: t2Price, 
      percentage: 30, 
      gain: ((parseFloat(t2Price) - entry) / entry * 100).toFixed(2) + '%'
    },
    t3: { 
      price: t3Price, 
      percentage: 20, 
      gain: ((parseFloat(t3Price) - entry) / entry * 100).toFixed(2) + '%'
    }
  };
}

function determineTimeHorizon(flow) {
  const badges = flow.badgesRaw || flow.badges || {};
  const session = flow.session_bucket;
  const hasFlash = badges.flash === '⚡';
  const score = flow.rocketScore || flow.rocket_score || 0;
  const more = badges.more || '';
  
  // SCALP (minutes to 1 hour)
  if (hasFlash && session === 'RTH' && score >= 5) {
    return {
      expected: '15-60 minutes',
      maxHold: 'End of day',
      style: 'SCALP'
    };
  }
  
  // INTRADAY (1-4 hours)
  if (session === 'RTH' && score >= 3) {
    return {
      expected: '2-4 hours',
      maxHold: 'End of day',
      style: 'INTRADAY'
    };
  }
  
  // SWING (1-5 days)
  if (more.includes('💎') && !hasFlash) {
    return {
      expected: '1-3 days',
      maxHold: '5 days',
      style: 'SWING'
    };
  }
  
  // DEFAULT
  return {
    expected: '2-4 hours',
    maxHold: 'End of day',
    style: 'INTRADAY'
  };
}

function buildReasoning(flow) {
  const reasons = [];
  const catalysts = [];
  const risks = [];
  const badges = flow.badgesRaw || flow.badges || {};
  const more = badges.more || '';
  
  // WHY reasons - dynamic based on actual data
  if (more.includes('💎')) {
    const itmBull = flow.prem_cb_itm || 0;
    const itmBear = flow.prem_ps_itm || 0;
    const itmTotal = itmBull + itmBear;
    const itmDominance = itmTotal > 0 ? ((itmBull > itmBear ? itmBull : itmBear) / itmTotal * 100).toFixed(0) : 0;
    reasons.push(`ITM dominance (💎): ${itmDominance}% of flow in ITM options = real money positioning`);
  }
  if (more.includes('⭐')) {
    const otmBull = (flow.prem_cb_otm || 0) + (flow.prem_ps_otm || 0);
    const otmBear = (flow.prem_pb_otm || 0) + (flow.prem_cs_otm || 0);
    const otmTotal = otmBull + otmBear;
    if (otmTotal > 0) {
      // Format large numbers properly (avoid scientific notation)
      let otmDisplay;
      if (otmTotal >= 1e9) {
        otmDisplay = `$${(otmTotal / 1e9).toFixed(2)}B`;
      } else if (otmTotal >= 1e6) {
        otmDisplay = `$${(otmTotal / 1e6).toFixed(2)}M`;
      } else if (otmTotal >= 1e3) {
        otmDisplay = `$${(otmTotal / 1e3).toFixed(0)}K`;
      } else {
        otmDisplay = `$${otmTotal.toFixed(0)}`;
      }
      reasons.push(`OTM flow (⭐): ${otmDisplay} in OTM options = gamma squeeze potential`);
    } else {
      reasons.push(`OTM flow (⭐): Significant OTM positioning detected`);
    }
  }
  if (more.includes('💰')) {
    const oi = flow.oi_num || 0;
    if (oi > 0) {
      reasons.push(`High OI (💰): ${oi.toLocaleString()} open interest = magnetic strike zone`);
    } else {
      reasons.push(`High OI (💰): Elevated open interest = magnetic strike zone`);
    }
  }
  if (badges.flash === '⚡') {
    const premium = flow.premium_num || 0;
    if (premium > 0) {
      reasons.push(`Aggressive sweep (⚡): $${(premium / 1000).toFixed(0)}K urgent institutional execution`);
    } else {
      reasons.push(`Aggressive sweep (⚡): Urgent institutional execution`);
    }
  }
  if (flow.tapeAligned || flow.tape_alignment === 1) {
    const arrow = flow.tapeArrow || (flow.direction === 'BULL' ? '↗︎' : '↘︎');
    const priceChange = flow.price_change_pct || 0;
    if (priceChange !== 0) {
      reasons.push(`Tape aligned (${arrow}): Price ${priceChange > 0 ? 'up' : 'down'} ${Math.abs(priceChange).toFixed(2)}% confirming flow direction`);
    } else {
      reasons.push(`Tape aligned (${arrow}): Price confirming flow direction`);
    }
  }
  const premium = flow.premium_num || 0;
  if (premium > 1000000) {
    reasons.push(`Large premium (🔥): $${(premium / 1e6).toFixed(2)}M institutional size`);
  }
  
  // CATALYSTS
  if (flow.near_alert_type) {
    catalysts.push(`${flow.near_alert_type}: ${flow.near_alert_msg || 'Event detected'}`);
  }
  
  // RISKS
  if (flow.session_bucket === 'PRE') {
    risks.push(`Pre-market session: Wait for RTH confirmation to avoid retail noise`);
  }
  if (!flow.tapeAligned && flow.tape_alignment !== 1) {
    const priceChange = flow.price_change_pct || 0;
    if (priceChange !== 0) {
      risks.push(`No tape alignment: Price ${priceChange > 0 ? 'up' : 'down'} ${Math.abs(priceChange).toFixed(2)}% but flow suggests opposite (potential trap)`);
    } else {
      risks.push(`No tape alignment: Price not confirming flow (potential trap)`);
    }
  }
  const lastFlowMinutes = flow.lastFlowMinutes || 0;
  if (lastFlowMinutes > 30) {
    risks.push(`Flow fading: Last institutional activity ${lastFlowMinutes}min ago`);
  }
  
  return { why: reasons, catalysts, risks };
}

function setInvalidationConditions(flow, wideStop) {
  const conditions = [];
  
  if (wideStop) {
    conditions.push(`Exit if price breaks below $${wideStop} (institutions wrong)`);
  }
  conditions.push(`Exit if no follow-through within 30 minutes`);
  conditions.push(`Exit if flow reverses direction (badge color flips)`);
  conditions.push(`Exit if new opposing flow appears (>$500K opposite direction)`);
  
  return {
    priceLevel: wideStop,
    conditions
  };
}

function calculateRiskReward(entry, stop, target) {
  if (!entry || !stop || !target) return { risk: null, reward: null, ratio: null };
  
  const entryNum = parseFloat(entry);
  const stopNum = parseFloat(stop);
  const targetNum = parseFloat(target);
  
  const risk = Math.abs((stopNum - entryNum) / entryNum * 100);
  const reward = Math.abs((targetNum - entryNum) / entryNum * 100);
  const ratio = (reward / risk).toFixed(2);
  
  return {
    risk: risk.toFixed(2) + '%',
    reward: reward.toFixed(2) + '%',
    ratio: ratio + ':1'
  };
}

/**
 * Calculate readiness score (what % of requirements are met)
 * This should be calculated from the plan data, not hardcoded
 */
function calculateReadiness(plan) {
  if (!plan || plan.signal !== 'WAIT') {
    return plan?.confidence || 0;
  }
  
  let score = 0;
  const maxScore = 100;
  
  // Confidence contributes to readiness (60% weight)
  score += (plan.confidence || 0) * 0.6;
  
  // Check if entry strategy exists (15 points)
  if (plan.entry && plan.entry.primary) score += 15;
  else if (plan.entry && plan.entry.conditionalTriggers && plan.entry.conditionalTriggers.length > 0) score += 10;
  
  // Check if stop loss exists (10 points)
  if (plan.stopLoss && plan.stopLoss.tight) score += 10;
  
  // Check if targets exist (10 points)
  if (plan.targets && plan.targets.t1 && plan.targets.t1.price) score += 10;
  
  // Check if reasoning exists (5 points)
  if (plan.reasoning && plan.reasoning.why && plan.reasoning.why.length > 0) score += 5;
  
  return Math.min(Math.round(score), maxScore);
}

/**
 * Generate dynamic wait status message based on plan data
 */
function generateWaitStatusMessage(plan, flowData) {
  if (!plan || plan.signal !== 'WAIT') return null;
  
  const missingFactors = [];
  const tapeAligned = flowData.tapeAligned || flowData.tape_alignment === 1;
  const confidence = plan.confidence || 0;
  const lastFlowMinutes = flowData.lastFlowMinutes || 999;
  
  // Check tape alignment (most common reason for WAIT)
  if (!tapeAligned) {
    missingFactors.push('Price not confirming');
  }
  
  // Check confidence threshold
  if (confidence < 50) {
    missingFactors.push('Low confidence');
  }
  
  // Check flow freshness
  if (lastFlowMinutes > 30 && confidence < 70) {
    missingFactors.push('Stale flow');
  }
  
  // Check for sufficient badges/signals
  if (confidence < 60) {
    missingFactors.push('Need more signals');
  }
  
  // Use first missing factor or default message
  if (missingFactors.length > 0) {
    return missingFactors[0];
  }
  
  return 'Low Conviction';
}

/**
 * Format trade plan for display/API response
 * Converts the trade plan object into a nicely formatted structure
 * 
 * @param {Object} tradePlan - The trade plan object from generateTradePlan
 * @returns {Object} Formatted trade plan
 */
export function formatTradePlan(tradePlan) {
  if (!tradePlan) return null;
  
  return {
    symbol: tradePlan.symbol,
    signal: tradePlan.signal,
    confidence: tradePlan.confidence,
    readiness: tradePlan.readiness,
    waitStatusMessage: tradePlan.waitStatusMessage,
    
    entry: {
      primary: tradePlan.entry?.primary,
      aggressive: tradePlan.entry?.aggressive,
      reasoning: tradePlan.entry?.reasoning,
      conditionalTriggers: tradePlan.entry?.conditionalTriggers
    },
    
    stopLoss: {
      tight: tradePlan.stopLoss?.tight,
      wide: tradePlan.stopLoss?.wide,
      reasoning: tradePlan.stopLoss?.reasoning
    },
    
    targets: {
      t1: {
        price: tradePlan.targets?.t1?.price,
        percentage: tradePlan.targets?.t1?.percentage,
        gain: tradePlan.targets?.t1?.gain
      },
      t2: {
        price: tradePlan.targets?.t2?.price,
        percentage: tradePlan.targets?.t2?.percentage,
        gain: tradePlan.targets?.t2?.gain
      },
      t3: {
        price: tradePlan.targets?.t3?.price,
        percentage: tradePlan.targets?.t3?.percentage,
        gain: tradePlan.targets?.t3?.gain
      }
    },
    
    timeHorizon: {
      expected: tradePlan.timeHorizon?.expected,
      maxHold: tradePlan.timeHorizon?.maxHold,
      style: tradePlan.timeHorizon?.style
    },
    
    reasoning: {
      why: tradePlan.reasoning?.why || [],
      catalysts: tradePlan.reasoning?.catalysts || [],
      risks: tradePlan.reasoning?.risks || []
    },
    
    invalidation: {
      priceLevel: tradePlan.invalidation?.priceLevel,
      conditions: tradePlan.invalidation?.conditions || []
    },
    
    riskReward: {
      risk: tradePlan.riskReward?.risk,
      reward: tradePlan.riskReward?.reward,
      ratio: tradePlan.riskReward?.ratio
    },
    
    historicalEdge: {
      similarSetups: tradePlan.historicalEdge?.similarSetups || 0,
      winRate: tradePlan.historicalEdge?.winRate || 0,
      avgWin: tradePlan.historicalEdge?.avgWin || 0,
      avgLoss: tradePlan.historicalEdge?.avgLoss || 0,
      expectancy: tradePlan.historicalEdge?.expectancy || 0
    }
  };
}
