import { canonicalTeam } from '../../../src/lib/teams';
import type { LiveMatch } from '../tournament';
import type { MatchStatus } from '../../../src/lib/types';

// Pure ESPN normalizers — no network or DB, so they're unit-testable in
// isolation (and don't drag node:sqlite into the Vite test graph).

interface EspnCompetitor {
  homeAway: 'home' | 'away';
  team: { id: string; displayName: string; name?: string; abbreviation?: string };
  score?: string;
}
interface EspnStatus { type: { state: 'pre' | 'in' | 'post'; completed?: boolean; name?: string }; displayClock?: string; period?: number }
export interface EspnEvent {
  id: string;
  date: string;
  name: string;
  competitions: { competitors: EspnCompetitor[]; venue?: { fullName?: string } }[];
  status: EspnStatus;
}

export interface EspnMatch extends LiveMatch {
  eventId: string;
}

function mapStatus(s: EspnStatus): MatchStatus {
  if (s.type.state === 'in') return 'live';
  if (s.type.state === 'post') return 'finished';
  return 'scheduled';
}

function parseMinute(s: EspnStatus): number | null {
  if (s.type.state !== 'in') return null;
  const m = s.displayClock?.match(/(\d+)/);
  return m ? Number(m[1]) : (s.period ? (s.period - 1) * 45 : null);
}

/** Scoreboard body → matches with ESPN event ids. */
export function normalizeScoreboard(body: { events?: EspnEvent[] }): EspnMatch[] {
  const out: EspnMatch[] = [];
  for (const e of body.events ?? []) {
    const comp = e.competitions[0];
    if (!comp) continue;
    const home = comp.competitors.find((c) => c.homeAway === 'home');
    const away = comp.competitors.find((c) => c.homeAway === 'away');
    if (!home || !away) continue;
    out.push({
      eventId: e.id,
      home: canonicalTeam(home.team.displayName),
      away: canonicalTeam(away.team.displayName),
      group: null,
      stage: 'group',
      kickoff: e.date,
      homeScore: home.score != null && home.score !== '' ? Number(home.score) : null,
      awayScore: away.score != null && away.score !== '' ? Number(away.score) : null,
      status: mapStatus(e.status),
      minute: parseMinute(e.status),
    });
  }
  return out;
}

// ---- summary (rich enrichment) ----
export interface EspnH2HGame { date: string; homeTeamId: string; awayTeamId: string; homeScore: number; awayScore: number }
export interface EspnTeamRef { id: string; name: string; homeAway: 'home' | 'away' }
export interface EspnLineupPlayer { name: string; position: string | null; starter: boolean; number: number | null }
export interface EspnSummary {
  fetchedAt: number;
  venue: string | null;
  teams: EspnTeamRef[];
  h2h: EspnH2HGame[];
  /** Recent results per team id, most recent first: 'W' | 'D' | 'L'. */
  form: Record<string, string[]>;
  lineups: Record<string, EspnLineupPlayer[]>;
  /** Team match stats (possession, shots, …) once the game is live/finished. */
  stats: Record<string, Record<string, string>>;
}

export interface RawSummary {
  gameInfo?: { venue?: { fullName?: string } };
  header?: { competitions?: { competitors?: { id: string; team?: { displayName?: string }; homeAway: 'home' | 'away' }[] }[] };
  headToHeadGames?: { events?: { gameDate: string; homeTeamId: string; awayTeamId: string; homeTeamScore: string; awayTeamScore: string }[] }[];
  boxscore?: {
    form?: { team?: { id: string }; events?: { gameResult?: string }[] }[];
    teams?: { team?: { id: string }; statistics?: { name: string; displayValue: string }[] }[];
  };
  rosters?: { team?: { id: string }; roster?: { athlete?: { displayName?: string }; position?: { abbreviation?: string }; starter?: boolean; jersey?: string }[] }[];
}

export function normalizeSummary(raw: RawSummary): EspnSummary {
  const teams: EspnTeamRef[] = (raw.header?.competitions?.[0]?.competitors ?? []).map((c) => ({
    id: c.id,
    name: canonicalTeam(c.team?.displayName ?? ''),
    homeAway: c.homeAway,
  }));

  const h2h: EspnH2HGame[] = (raw.headToHeadGames?.[0]?.events ?? []).map((g) => ({
    date: g.gameDate,
    homeTeamId: g.homeTeamId,
    awayTeamId: g.awayTeamId,
    homeScore: Number(g.homeTeamScore),
    awayScore: Number(g.awayTeamScore),
  }));

  const form: Record<string, string[]> = {};
  for (const f of raw.boxscore?.form ?? []) {
    const id = f.team?.id;
    if (!id) continue;
    form[id] = (f.events ?? []).map((e) => (e.gameResult ?? '').toUpperCase()).filter(Boolean);
  }

  const lineups: Record<string, EspnLineupPlayer[]> = {};
  for (const r of raw.rosters ?? []) {
    const id = r.team?.id;
    if (!id) continue;
    lineups[id] = (r.roster ?? []).map((p) => ({
      name: p.athlete?.displayName ?? '',
      position: p.position?.abbreviation ?? null,
      starter: !!p.starter,
      number: p.jersey ? Number(p.jersey) : null,
    }));
  }

  const stats: Record<string, Record<string, string>> = {};
  for (const t of raw.boxscore?.teams ?? []) {
    const id = t.team?.id;
    if (!id) continue;
    stats[id] = Object.fromEntries((t.statistics ?? []).map((s) => [s.name, s.displayValue]));
  }

  return { fetchedAt: Date.now(), venue: raw.gameInfo?.venue?.fullName ?? null, teams, h2h, form, lineups, stats };
}
