import type { LiveMatch } from './tournament'; import type { MatchStatus, Stage } from '../../src/lib/types'; // football-data.org v4 — the reliable (if delayed) free source. // Free tier: World Cup is included, 10 req/min. We poll one endpoint (~1 req/min). const BASE = 'https://api.football-data.org/v4'; const COMPETITION = 'WC'; interface FdTeam { name: string | null } interface FdScore { home: number | null; away: number | null } interface FdMatch { status: string; stage: string; group: string | null; utcDate: string; minute?: number | null; homeTeam: FdTeam; awayTeam: FdTeam; score: { fullTime: FdScore }; } function mapStatus(s: string): MatchStatus | null { switch (s) { case 'SCHEDULED': case 'TIMED': return 'scheduled'; case 'IN_PLAY': case 'PAUSED': return 'live'; case 'FINISHED': return 'finished'; default: return null; // POSTPONED / SUSPENDED / CANCELLED — ignore } } function mapStage(s: string): Stage | null { switch (s) { case 'GROUP_STAGE': return 'group'; case 'LAST_32': return 'r32'; case 'LAST_16': return 'r16'; case 'QUARTER_FINALS': return 'qf'; case 'SEMI_FINALS': return 'sf'; case 'THIRD_PLACE': return 'third'; case 'FINAL': return 'final'; default: return null; } } export async function fetchFootballData(token: string): Promise { const res = await fetch(`${BASE}/competitions/${COMPETITION}/matches`, { headers: { 'X-Auth-Token': token }, signal: AbortSignal.timeout(12_000), }); if (!res.ok) throw new Error(`football-data ${res.status}`); const body = (await res.json()) as { matches?: FdMatch[] }; const out: LiveMatch[] = []; for (const m of body.matches ?? []) { const status = mapStatus(m.status); const stage = mapStage(m.stage); if (!status || !stage || !m.homeTeam.name || !m.awayTeam.name) continue; out.push({ home: m.homeTeam.name, away: m.awayTeam.name, group: m.group ? m.group.replace('GROUP_', '') : null, stage, kickoff: m.utcDate, homeScore: m.score.fullTime.home, awayScore: m.score.fullTime.away, status, minute: m.minute ?? null, }); } return out; }