import pool from '../src/db';
import { getCachedForecast, type RmForecast } from '../src/models/forecast';
import { refreshForEvent } from '../src/services/forecast-runner';
import { fetchEvents, type SgoEvent } from '../src/services/sgo';

type RepairTargetRow = {
  event_id: string;
  home_team: string;
  away_team: string;
  starts_at: string;
};

function getEtStartOfDayIso(): string {
  const now = new Date();
  const et = new Date(now.toLocaleString('en-US', { timeZone: 'America/New_York' }));
  const year = et.getFullYear();
  const month = String(et.getMonth() + 1).padStart(2, '0');
  const day = String(et.getDate()).padStart(2, '0');
  return `${year}-${month}-${day}T00:00:00-05:00`;
}

function findMatchingEvent(target: RepairTargetRow, events: SgoEvent[]): SgoEvent | null {
  const direct = events.find((event) => event.eventID === target.event_id);
  if (direct) return direct;

  const targetDate = new Date(target.starts_at).toISOString().slice(0, 10);
  return events.find((event) => {
    const startsAt = event.status?.startsAt || '';
    return (
      event.teams?.home?.names?.long === target.home_team
      && event.teams?.away?.names?.long === target.away_team
      && startsAt.slice(0, 10) === targetDate
    );
  }) || null;
}

async function stampRepair(cachedId: string): Promise<void> {
  await pool.query(
    `UPDATE rm_forecast_cache
       SET last_refresh_at = NOW(),
           last_refresh_type = 'rie_payload_repair',
           refresh_count = COALESCE(refresh_count, 0) + 1
     WHERE id = $1`,
    [cachedId],
  );
}

async function main() {
  const startsAfter = getEtStartOfDayIso();
  const { rows } = await pool.query<RepairTargetRow>(
    `SELECT event_id, home_team, away_team, starts_at
       FROM rm_forecast_cache
      WHERE league = 'mlb'
        AND DATE(created_at AT TIME ZONE 'America/New_York') = CURRENT_DATE
        AND composite_version = 'rie-v1'
        AND NOT (model_signals ? 'rieSignals')
      ORDER BY created_at ASC`,
  );

  if (rows.length === 0) {
    console.log('No stale MLB rie-v1 rows missing payload-v2 fields.');
    await pool.end();
    return;
  }

  const events = await fetchEvents('mlb', startsAfter);
  let refreshed = 0;
  let failed = 0;
  let missingLiveEvent = 0;

  for (const row of rows) {
    const liveEvent = findMatchingEvent(row, events);
    if (!liveEvent) {
      missingLiveEvent += 1;
      console.log(`[SKIP] ${row.event_id} — no live SGO event match`);
      continue;
    }

    const cached = await getCachedForecast(row.event_id);
    if (!cached) {
      failed += 1;
      console.log(`[FAIL] ${row.event_id} — cached row disappeared`);
      continue;
    }

    try {
      await refreshForEvent(liveEvent, 'mlb', cached as RmForecast, `[RIE-PAYLOAD-REPAIR] ${row.event_id}`);
      await stampRepair(cached.id);
      refreshed += 1;
      console.log(`[OK] ${row.event_id}`);
    } catch (error: any) {
      failed += 1;
      console.error(`[FAIL] ${row.event_id}: ${error?.message || error}`);
    }
  }

  const verification = await pool.query<{ remaining: string }>(
    `SELECT COUNT(*)::text AS remaining
       FROM rm_forecast_cache
      WHERE league = 'mlb'
        AND DATE(created_at AT TIME ZONE 'America/New_York') = CURRENT_DATE
        AND composite_version = 'rie-v1'
        AND NOT (model_signals ? 'rieSignals')`,
  );

  console.log(
    JSON.stringify({
      targets: rows.length,
      refreshed,
      failed,
      missingLiveEvent,
      remaining: Number(verification.rows[0]?.remaining || 0),
    }),
  );

  await pool.end();
}

main().catch(async (error) => {
  console.error(error);
  await pool.end();
  process.exit(1);
});
