// openfootball worldcup-2026.json → public/data/fixtures.json
// Normalizes the 104 matches into the app's Fixture shape: canonical team names,
// ISO-UTC kickoffs, stage tags, and pretty knockout placeholder labels.
import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
import { canonicalTeam } from '../src/lib/teams';
import type { Fixture, FixturesFile, Stage, TeamSlot } from '../src/lib/types';

const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
const RAW = join(ROOT, 'data', 'raw', 'worldcup-2026.json');
const OUT_DIR = join(ROOT, 'public', 'data');

interface RawMatch {
  round: string;
  num?: number;
  date: string;
  time: string;
  team1: string;
  team2: string;
  group?: string;
  ground: string;
}

function stageOf(round: string): Stage {
  if (round.startsWith('Matchday')) return 'group';
  if (round.startsWith('Round of 32')) return 'r32';
  if (round.startsWith('Round of 16')) return 'r16';
  if (round.startsWith('Quarter')) return 'qf';
  if (round.startsWith('Semi')) return 'sf';
  if (round.startsWith('Match for third')) return 'third';
  if (round.startsWith('Final')) return 'final';
  throw new Error(`Unknown round: ${round}`);
}

/** "2026-06-11" + "13:00 UTC-6" → ISO 8601 UTC. */
function toIsoUtc(date: string, time: string): string {
  const [y, mo, d] = date.split('-').map(Number);
  const m = time.match(/^(\d{1,2}):(\d{2})\s*UTC([+-]\d{1,2})$/);
  if (!m || y === undefined || mo === undefined || d === undefined) {
    throw new Error(`Bad date/time: ${date} ${time}`);
  }
  const hh = Number(m[1]);
  const mm = Number(m[2]);
  const offset = Number(m[3]); // local = UTC + offset, so UTC hour = hh - offset
  return new Date(Date.UTC(y, mo - 1, d, hh - offset, mm)).toISOString();
}

/** Knockout placeholder code → readable label. */
function placeholderLabel(code: string): string {
  const pos = code.match(/^([123])([A-L])$/);
  if (pos) {
    const rank = pos[1] === '1' ? 'Winner' : pos[1] === '2' ? 'Runner-up' : '3rd';
    return `${rank} Group ${pos[2]}`;
  }
  const third = code.match(/^3([A-L/]+)$/);
  if (third) return `3rd: ${third[1]}`;
  const wl = code.match(/^([WL])(\d{1,3})$/);
  if (wl) return `${wl[1] === 'W' ? 'Winner' : 'Loser'} of M${wl[2]}`;
  return code;
}

function slot(raw: string, isGroup: boolean): TeamSlot {
  if (isGroup) {
    const team = canonicalTeam(raw);
    return { team, placeholder: null, label: team };
  }
  return { team: null, placeholder: raw, label: placeholderLabel(raw) };
}

function main(): void {
  const raw = JSON.parse(readFileSync(RAW, 'utf8')) as { name: string; matches: RawMatch[] };
  const matches = raw.matches;

  // groupRound: order each group's matches by kickoff, 2 matches per round.
  const groupOrder = new Map<string, number>(); // `${group}#${num}` → 0-based index
  const byGroup = new Map<string, { num: number; iso: string }[]>();

  const prelim = matches.map((m, i) => {
    const stage = stageOf(m.round);
    const num = m.num ?? i + 1;
    const iso = toIsoUtc(m.date, m.time);
    if (stage === 'group' && m.group) {
      const g = m.group.replace('Group ', '');
      if (!byGroup.has(g)) byGroup.set(g, []);
      byGroup.get(g)!.push({ num, iso });
    }
    return { m, stage, num, iso };
  });
  for (const [g, list] of byGroup) {
    list.sort((a, b) => a.iso.localeCompare(b.iso) || a.num - b.num);
    list.forEach((x, idx) => groupOrder.set(`${g}#${x.num}`, idx));
  }

  const fixtures: Fixture[] = prelim.map(({ m, stage, num, iso }) => {
    const group = stage === 'group' && m.group ? m.group.replace('Group ', '') : null;
    const groupRound = group ? Math.floor((groupOrder.get(`${group}#${num}`) ?? 0) / 2) + 1 : null;
    return {
      num,
      stage,
      group,
      round: m.round,
      groupRound,
      kickoff: iso,
      venue: m.ground,
      home: slot(m.team1, stage === 'group'),
      away: slot(m.team2, stage === 'group'),
      status: 'scheduled',
      homeScore: null,
      awayScore: null,
      minute: null,
    } satisfies Fixture;
  });

  fixtures.sort((a, b) => a.num - b.num);

  const out: FixturesFile = {
    season: raw.name,
    generatedAt: new Date().toISOString(),
    groups: [...new Set(fixtures.filter((f) => f.group).map((f) => f.group!))].sort(),
    venues: [...new Set(fixtures.map((f) => f.venue))].sort(),
    fixtures,
  };

  mkdirSync(OUT_DIR, { recursive: true });
  writeFileSync(join(OUT_DIR, 'fixtures.json'), JSON.stringify(out));
  console.log(
    `fixtures → public/data/fixtures.json  (${fixtures.length} matches, ${out.groups.length} groups, ${out.venues.length} venues)`,
  );
}

main();
