import type { MatchRecord, MatchSyncAdapter, MatchStatusValue } from "./types"; interface EspnCompetitor { id: string; team: { id: string; displayName: string; abbreviation?: string }; score?: string; homeAway?: "home" | "away"; winner?: boolean; } interface EspnEvent { id: string; date: string; competitions?: Array<{ competitors?: EspnCompetitor[]; status?: { type?: { name?: string; completed?: boolean; description?: string } }; matchday?: number; }>; } interface EspnScheduleResponse { events?: EspnEvent[]; } function mapStatus(name: string | undefined, completed: boolean | undefined): MatchStatusValue { if (completed) return "complete"; if (name === "STATUS_IN_PROGRESS" || name === "in_progress") return "in_progress"; if (name === "STATUS_CANCELED" || name === "canceled") return "canceled"; if (name === "STATUS_POSTPONED" || name === "postponed") return "postponed"; return "scheduled"; } export class EspnScheduleAdapter implements MatchSyncAdapter { readonly supportsLiveScores = false; private readonly sport: string; // e.g. "baseball/mlb", "basketball/nba" constructor(sport: string) { this.sport = sport; } // externalSeasonId is "YYYY" year string for ESPN sports async fetchMatches(externalSeasonId: string): Promise { const url = `https://site.api.espn.com/apis/site/v2/sports/${this.sport}/scoreboard?limit=1000&dates=${externalSeasonId}`; const resp = await fetch(url); if (!resp.ok) { const body = await resp.text(); throw new Error(`ESPN API error ${resp.status}: ${body}`); } const data = (await resp.json()) as EspnScheduleResponse; const matches: MatchRecord[] = []; for (const event of data.events ?? []) { const comp = event.competitions?.[0]; if (!comp) continue; const competitors = comp.competitors ?? []; const home = competitors.find((c) => c.homeAway === "home") ?? competitors[0]; const away = competitors.find((c) => c.homeAway === "away") ?? competitors[1]; if (!home || !away) continue; const statusType = comp.status?.type; const status = mapStatus(statusType?.name, statusType?.completed); const homeScore = home.score ? parseInt(home.score, 10) : null; const awayScore = away.score ? parseInt(away.score, 10) : null; const winnerExternalId = home.winner ? home.team.id : away.winner ? away.team.id : null; matches.push({ externalMatchId: event.id, team1ExternalId: home.team.id, team1Name: home.team.displayName, team2ExternalId: away.team.id, team2Name: away.team.displayName, team1Score: homeScore, team2Score: awayScore, winnerExternalId, status, scheduledAt: new Date(event.date), startedAt: status !== "scheduled" ? new Date(event.date) : null, completedAt: status === "complete" ? new Date(event.date) : null, matchStage: null, matchRound: null, matchday: comp.matchday ?? null, isSeries: false, }); } return matches; } }