/**
 * Daily Archive Settlement Backfill
 *
 * Catches any archived forecasts that were missed by the resolve-forecasts worker.
 * Looks for pending archived forecasts older than 4 hours and tries to settle them.
 *
 * Usage: npx tsx src/workers/settle-archives.ts
 * Cron: 0 7 * * * (2 AM ET daily)
 */

import dotenv from 'dotenv';
import path from 'path';
dotenv.config({ path: path.join(__dirname, '../../.env') });

import pool from '../db';
import { refreshBucketStats, settleArchivedForecast, voidArchivedForecast } from '../services/archive';
import { findFinalResult } from '../services/final-result-service';

const STALE_ARCHIVE_VOID_THRESHOLD_HOURS = 24 * 7;

export function shouldVoidStaleArchive(startsAt: string | Date, now = new Date()): boolean {
  const startedAt = startsAt instanceof Date ? startsAt : new Date(startsAt);
  if (Number.isNaN(startedAt.getTime())) return false;
  return now.getTime() - startedAt.getTime() >= STALE_ARCHIVE_VOID_THRESHOLD_HOURS * 60 * 60 * 1000;
}

export async function runArchiveSettlementBackfill(options: {
  refreshBuckets?: boolean;
  closePool?: boolean;
} = {}) {
  const { refreshBuckets = true, closePool = false } = options;
  console.log(`[${new Date().toISOString()}] Starting archive settlement backfill...`);

  try {
    // Find pending archived forecasts older than 4 hours
    const { rows: pending } = await pool.query(
      `SELECT af.id, af.forecast_id, af.event_id, af.league, af.home_team, af.away_team,
              af.starts_at, af.winner_pick
       FROM rm_archived_forecasts af
       WHERE af.outcome = 'pending'
         AND af.starts_at < NOW() - interval '4 hours'
       ORDER BY af.starts_at ASC
       LIMIT 1000`
    );

    console.log(`Found ${pending.length} pending archived forecasts to settle`);

    let settled = 0;
    let voided = 0;

    for (const archive of pending) {
      try {
        const accuracy = await pool.query(
          `SELECT fa.actual_winner, fa.final_grade, fa.accuracy_pct, fa.home_score, fa.away_score
           FROM rm_forecast_accuracy_v2 fa
           WHERE fa.forecast_id = $1
              OR fa.event_id = $2
           LIMIT 1`,
          [archive.forecast_id, archive.event_id]
        );
        const accRows = accuracy.rows;

        if (accRows.length > 0) {
          const grade = String(accRows[0].final_grade || '').trim().toUpperCase();
          const outcome = grade === 'W'
            ? 'win'
            : grade === 'P'
              ? 'push'
              : accRows[0].actual_winner === 'DRAW'
                ? 'push'
                : accRows[0].accuracy_pct >= 50 ? 'win' : 'loss';
          const score = accRows[0].home_score != null && accRows[0].away_score != null
            ? `${accRows[0].home_score}-${accRows[0].away_score}`
            : '';
          await settleArchivedForecast(archive.id, outcome as any, accRows[0].actual_winner || '', score);
          settled++;
          console.log(`  Settled (from accuracy): ${archive.away_team} @ ${archive.home_team} → ${outcome}`);
          continue;
        }

        const result = await findFinalResult({
          league: archive.league,
          startsAt: archive.starts_at,
          homeTeam: archive.home_team,
          awayTeam: archive.away_team,
        });
        if (!result) {
          if (!shouldVoidStaleArchive(archive.starts_at)) continue;

          await voidArchivedForecast(
            archive.id,
            `void: unresolved result after ${STALE_ARCHIVE_VOID_THRESHOLD_HOURS}h`,
            'VOID_UNRESOLVED_STALE_RESULT',
          );
          voided++;
          console.log(`  Voided stale unresolved archive: ${archive.away_team} @ ${archive.home_team}`);
          continue;
        }

        const actualWinner = result.homeScore === result.awayScore
          ? 'DRAW'
          : result.homeScore > result.awayScore ? archive.home_team : archive.away_team;
        const predictedWinner = archive.winner_pick || '';
        const outcome = actualWinner === 'DRAW'
          ? 'push'
          : predictedWinner.toLowerCase().includes(actualWinner.toLowerCase().split(' ').pop() || '')
            ? 'win'
            : 'loss';
        const score = `${result.homeScore}-${result.awayScore}`;

        await settleArchivedForecast(archive.id, outcome as any, actualWinner, score);
        settled++;
        console.log(`  Settled (from ${result.source}): ${archive.away_team} @ ${archive.home_team} → ${outcome} (${score})`);
      } catch (err: any) {
        console.error(`  Failed to settle archive ${archive.id}: ${err.message}`);
      }
    }

    // Refresh bucket stats
    if (refreshBuckets) {
      await refreshBucketStats();
    }
    console.log(`\nSettlement complete. Settled: ${settled}/${pending.length}, voided stale: ${voided}`);
  } catch (err) {
    console.error('Settlement backfill error:', err);
  }

  if (closePool) {
    await pool.end();
  }
}

async function main() {
  await runArchiveSettlementBackfill({ closePool: true });
}

if (require.main === module) {
  main().catch((err) => {
    console.error('Fatal error:', err);
    process.exit(1);
  });
}
