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

import pool from '../db';

type EspnFightRow = {
  fightId: string;
  fighter1Id: string;
  fighter2Id: string;
  fighter1Name: string;
  fighter2Name: string;
  weightClass: string | null;
  method: string | null;
  round: number | null;
  fightTime: string | null;
  result1: string;
  result2: string;
  referee: string | null;
  methodDetails: string | null;
  raw: any;
};

function normalizeName(value: string | null | undefined): string {
  return String(value || '')
    .normalize('NFD')
    .replace(/[\u0300-\u036f]/g, '')
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '');
}

function pickEspnEvent(localName: string, espnEvents: any[]): any | null {
  const exact = espnEvents.find((entry: any) => normalizeName(entry?.name) === normalizeName(localName));
  if (exact) return exact;

  if (espnEvents.length === 1) return espnEvents[0];

  const localTokens = normalizeName(localName);
  const partial = espnEvents.find((entry: any) => {
    const normalized = normalizeName(entry?.name);
    return normalized && (normalized.includes(localTokens) || localTokens.includes(normalized));
  });
  return partial || null;
}

function getCompetitorName(entry: any): string {
  return entry?.athlete?.displayName
    || entry?.athlete?.fullName
    || entry?.team?.displayName
    || entry?.team?.name
    || '';
}

function getCompetitorId(entry: any): string {
  return String(entry?.athlete?.id || entry?.id || '');
}

function getResult(entry: any, opponent: any): string {
  if (entry?.winner === true) return 'W';
  if (entry?.winner === false && opponent?.winner === true) return 'L';
  if (entry?.winner === false && opponent?.winner === false) return 'D';
  return 'N';
}

function getMethod(competition: any): { method: string | null; methodDetails: string | null } {
  const detailTexts: string[] = Array.isArray(competition?.details)
    ? competition.details.map((detail: any) => String(detail?.type?.text || '').trim()).filter((text: string) => Boolean(text))
    : [];

  const resultDetail = detailTexts.find((text: string) => /Unofficial Winner/i.test(text)) || null;
  const method = resultDetail
    ? resultDetail.replace(/^Unofficial Winner\s+/i, '').trim() || 'Decision'
    : null;
  return {
    method,
    methodDetails: detailTexts.join(' | ') || null,
  };
}

function toFightRow(localEventId: string, competition: any): EspnFightRow | null {
  const competitors = Array.isArray(competition?.competitors) ? competition.competitors : [];
  if (competitors.length < 2) return null;

  const fighter1 = competitors.find((entry: any) => entry.order === 1) || competitors[0];
  const fighter2 = competitors.find((entry: any) => entry.order === 2) || competitors[1];

  const fighter1Name = getCompetitorName(fighter1);
  const fighter2Name = getCompetitorName(fighter2);
  if (!fighter1Name || !fighter2Name) return null;

  const { method, methodDetails } = getMethod(competition);

  return {
    fightId: String(competition?.id || `${localEventId}:${normalizeName(fighter1Name)}:${normalizeName(fighter2Name)}`),
    fighter1Id: getCompetitorId(fighter1),
    fighter2Id: getCompetitorId(fighter2),
    fighter1Name,
    fighter2Name,
    weightClass: competition?.type?.abbreviation || null,
    method,
    round: Number.isFinite(Number(competition?.status?.period)) ? Number(competition.status.period) : null,
    fightTime: competition?.status?.displayClock || null,
    result1: getResult(fighter1, fighter2),
    result2: getResult(fighter2, fighter1),
    referee: null,
    methodDetails,
    raw: competition,
  };
}

async function fetchEspnCard(dateStr: string): Promise<any[]> {
  const url = `https://site.api.espn.com/apis/site/v2/sports/mma/ufc/scoreboard?dates=${dateStr}&limit=500`;
  const res = await fetch(url);
  if (!res.ok) return [];
  const data = await res.json() as any;
  return Array.isArray(data?.events) ? data.events : [];
}

async function main() {
  console.log(`[${new Date().toISOString()}] Backfilling UFC fights from ESPN...`);

  const { rows: missingEvents } = await pool.query(
    `SELECT e."eventId", e.name, e.date
     FROM "UfcEvent" e
     LEFT JOIN "UfcFight" f ON f."eventId" = e."eventId"
     WHERE e.date >= NOW() - INTERVAL '90 days'
       AND e.name ILIKE 'UFC%'
     GROUP BY e."eventId", e.name, e.date
     HAVING COUNT(f.id) = 0
     ORDER BY e.date ASC`
  );

  let inserted = 0;
  let updated = 0;

  for (const event of missingEvents) {
    const dateStr = new Date(event.date).toISOString().slice(0, 10).replace(/-/g, '');
    const espnEvents = await fetchEspnCard(dateStr);
    const target = pickEspnEvent(event.name, espnEvents);
    if (!target) {
      console.warn(`[ufc-backfill] no ESPN card match for ${event.name} (${dateStr})`);
      continue;
    }

    const competitions = Array.isArray(target.competitions) ? target.competitions : [];
    for (const competition of competitions) {
      const fight = toFightRow(event.eventId, competition);
      if (!fight) continue;

      const result = await pool.query(
        `INSERT INTO "UfcFight"
         ("fightId", "eventId", "fighter1Id", "fighter2Id", "fighter1Name", "fighter2Name",
          "weightClass", method, round, "fightTime", result1, result2, referee, "methodDetails", raw, "updatedAt")
         VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,NOW())
         ON CONFLICT ("fightId") DO UPDATE SET
           "fighter1Id" = EXCLUDED."fighter1Id",
           "fighter2Id" = EXCLUDED."fighter2Id",
           "fighter1Name" = EXCLUDED."fighter1Name",
           "fighter2Name" = EXCLUDED."fighter2Name",
           "weightClass" = EXCLUDED."weightClass",
           method = EXCLUDED.method,
           round = EXCLUDED.round,
           "fightTime" = EXCLUDED."fightTime",
           result1 = EXCLUDED.result1,
           result2 = EXCLUDED.result2,
           referee = EXCLUDED.referee,
           "methodDetails" = EXCLUDED."methodDetails",
           raw = EXCLUDED.raw,
           "updatedAt" = NOW()
         RETURNING (xmax = 0) AS inserted`,
        [
          fight.fightId,
          event.eventId,
          fight.fighter1Id,
          fight.fighter2Id,
          fight.fighter1Name,
          fight.fighter2Name,
          fight.weightClass,
          fight.method,
          fight.round,
          fight.fightTime,
          fight.result1,
          fight.result2,
          fight.referee,
          fight.methodDetails,
          JSON.stringify(fight.raw),
        ],
      );

      if (result.rows[0]?.inserted) inserted++;
      else updated++;
    }

    console.log(`[ufc-backfill] ${event.name}: ${competitions.length} fights synced`);
  }

  console.log(`UFC fight backfill complete. inserted=${inserted} updated=${updated}`);
  await pool.end();
}

main().catch((err) => {
  console.error('UFC fight backfill failed:', err);
  process.exit(1);
});
