/**
 * Backfill clip_metadata into existing forecast_data for a single event (or all today's events).
 *
 * Usage:
 *   npx ts-node src/workers/backfill-clip-metadata.ts --event nba-was-orl-20260303
 *   npx ts-node src/workers/backfill-clip-metadata.ts --all-today
 *
 * This reads the stored forecast_data, computes deterministic clip_metadata
 * entries for every clippable element, and writes them back to rm_forecast_cache.
 * No LLM calls — pure data injection.
 */

import pool from '../db';

interface ClipEntry {
  entity_id: string;
  clip_type: string;
  display_text: string;
  clip_data?: Record<string, any>;
}

async function backfillEvent(eventId: string): Promise<boolean> {
  const { rows } = await pool.query(
    `SELECT id, event_id, home_team, away_team, league, forecast_data, odds_data, created_at
     FROM rm_forecast_cache WHERE event_id = $1`,
    [eventId]
  );

  if (rows.length === 0) {
    console.error(`[backfill] No forecast found for event_id=${eventId}`);
    return false;
  }

  const row = rows[0];
  const fd = row.forecast_data;
  const eid = row.event_id;
  const runDate = new Date(row.created_at).toISOString().slice(0, 10);

  // Build team short names from event_id pattern (e.g. nba-was-orl-20260303)
  const parts = eid.split('-');
  const awayShort = (parts[1] || '').toUpperCase();
  const homeShort = (parts[2] || '').toUpperCase();

  const clips: ClipEntry[] = [];

  // Derive projected margin from projected_margin OR projected_lines.spread
  const projMarginRaw = fd.projected_margin != null
    ? fd.projected_margin
    : (fd.projected_lines?.spread?.home ?? null);
  const projMarginAbs = projMarginRaw != null ? Math.abs(projMarginRaw) : null;
  const projTotal = fd.projected_total_points || fd.projected_lines?.total || null;

  // Determine favored team for spread
  const favTeam = projMarginRaw != null ? (projMarginRaw >= 0 ? homeShort : awayShort) : null;

  // 1) Spread clip target (no winner clip — removed per CLE)
  const spreadLine = fd.projected_lines?.spread?.home;
  const mktLine = spreadLine; // projected_lines.spread.home is the market spread
  if (favTeam && projMarginAbs != null) {
    const spreadSign = projMarginRaw >= 0 ? `-${projMarginAbs}` : `+${projMarginAbs}`;
    const mktSign = mktLine != null ? `${mktLine > 0 ? '+' : ''}${mktLine}` : '?';
    clips.push({
      entity_id: `game:${eid}:run:${runDate}:spread`,
      clip_type: 'SPREAD',
      display_text: `${awayShort} @ ${homeShort} | RM forecasted ${favTeam} ${spreadSign} | MKT ${homeShort} ${mktSign}`,
      clip_data: {
        clip_type: 'SPREAD',
        rm_forecast_value: projMarginRaw,
        mkt_value: mktLine,
        team_code: favTeam,
      },
    });
  }

  // 2) Game Total clip target
  const totalLine = fd.projected_lines?.total;
  if (projTotal != null) {
    const ou = totalLine != null ? (projTotal > totalLine ? 'O' : projTotal < totalLine ? 'U' : '=') : '?';
    clips.push({
      entity_id: `game:${eid}:run:${runDate}:total`,
      clip_type: 'TOTAL',
      display_text: `Game Total | RM forecasted ${projTotal} | MKT ${totalLine ?? '?'} | ${ou}`,
      clip_data: {
        clip_type: 'GAME_TOTAL',
        rm_forecast_value: projTotal,
        mkt_value: totalLine,
        total_type: 'GAME',
        ou_indicator: ou === '=' ? 'NONE' : ou,
      },
    });
  }

  // 3) Player prop highlights (from forecast_data.prop_highlights)
  if (Array.isArray(fd.prop_highlights)) {
    for (const p of fd.prop_highlights) {
      const playerName = p.player || 'Unknown';
      const stat = p.prop || 'stat';
      const dir = (p.recommendation || '').toUpperCase();
      const projVal = p.projected_stat_value;
      const line = p.market_line_value;

      const propDisplay = projVal != null
        ? `${playerName} ${stat.toUpperCase()} | RM forecasted ${projVal} | MKT ${line ?? '?'} | ${dir === 'OVER' ? 'O' : dir === 'UNDER' ? 'U' : dir}`
        : `${playerName} ${stat.toUpperCase()} | ${dir}`;

      const safePlayer = playerName.replace(/\s+/g, '_').toLowerCase();
      clips.push({
        entity_id: `pp:${eid}:run:${runDate}:${safePlayer}:${stat}`,
        clip_type: 'PLAYER_PROP',
        display_text: propDisplay,
        clip_data: {
          clip_type: 'PLAYER_PROP',
          rm_forecast_value: projVal,
          mkt_value: line,
          ou_indicator: dir === 'OVER' ? 'O' : dir === 'UNDER' ? 'U' : dir,
        },
      });
    }
  }

  // Write clip_metadata into forecast_data
  fd.clip_metadata = clips;

  await pool.query(
    `UPDATE rm_forecast_cache SET forecast_data = $1 WHERE event_id = $2`,
    [JSON.stringify(fd), eid]
  );

  console.log(`[backfill] ${eid}: injected ${clips.length} clip_metadata entries`);
  clips.forEach((c, i) => console.log(`  [${i}] ${c.clip_type}: ${c.display_text}`));
  return true;
}

async function main() {
  const args = process.argv.slice(2);

  if (args.includes('--all-today')) {
    // Backfill all of today's forecasts
    const today = new Date().toISOString().slice(0, 10);
    const { rows } = await pool.query(
      `SELECT event_id FROM rm_forecast_cache
       WHERE created_at::date = $1::date
         AND (forecast_data->'clip_metadata' IS NULL OR jsonb_array_length(forecast_data->'clip_metadata') = 0)`,
      [today]
    );
    console.log(`[backfill] Found ${rows.length} forecasts without clip_metadata for ${today}`);
    let ok = 0;
    for (const r of rows) {
      if (await backfillEvent(r.event_id)) ok++;
    }
    console.log(`[backfill] Done: ${ok}/${rows.length} updated`);
  } else {
    const eventIdx = args.indexOf('--event');
    if (eventIdx === -1 || !args[eventIdx + 1]) {
      console.error('Usage: backfill-clip-metadata.ts --event <event_id> | --all-today');
      process.exit(1);
    }
    const eventId = args[eventIdx + 1];
    const ok = await backfillEvent(eventId);
    if (!ok) process.exit(1);
  }

  await pool.end();
}

main().catch(err => {
  console.error('[backfill] Fatal error:', err);
  process.exit(1);
});
