import { readFileSync, existsSync } from 'node:fs';
import { getMatchExt } from './db/db';
import type { TournamentState } from './tournament';
import type { ModelEngine } from './model';
import type { EspnSummary } from './ingest/espnNormalize';
import type {
  H2HSummary, KeyPlayer, MatchPreview, StandingRow, TeamProfile,
} from '../../src/lib/types';

// Assembles a MatchPreview / TeamProfile from three layers: precomputed history
// (h2h.json, scorers.json), the DB's ESPN enrichment (form, lineups, venue), and
// the live model (prediction, odds, ratings).

interface H2HRecord {
  a: string; b: string;
  games: number; aWins: number; bWins: number; draws: number; aGoals: number; bGoals: number;
  last: { date: string; home: string; away: string; hs: number; as: number }[];
}

function loadStatic<T>(name: string): T {
  const candidates = [
    `${process.env.STATIC_DIR ?? ''}/data/${name}`,
    `${process.cwd()}/public/data/${name}`,
    `${process.cwd()}/dist/data/${name}`,
  ];
  for (const p of candidates) if (p && existsSync(p)) return JSON.parse(readFileSync(p, 'utf8')) as T;
  throw new Error(`${name} not found — run "npm run data:preview". Looked in: ${candidates.join(', ')}`);
}

let _h2h: Record<string, H2HRecord> | null = null;
let _scorers: Record<string, KeyPlayer[]> | null = null;
let _ratings: { ratings: Record<string, number> } | null = null;
const h2hData = () => (_h2h ??= loadStatic<Record<string, H2HRecord>>('h2h.json'));
const scorersData = () => (_scorers ??= loadStatic<Record<string, KeyPlayer[]>>('scorers.json'));
const ratingsData = () => (_ratings ??= loadStatic<{ ratings: Record<string, number> }>('ratings.json'));

const pairKey = (a: string, b: string) => [a, b].sort().join('|');

function h2hSummary(home: string, away: string): H2HSummary | null {
  const rec = h2hData()[pairKey(home, away)];
  if (!rec) return null;
  const homeIsA = home === rec.a;
  return {
    games: rec.games,
    homeWins: homeIsA ? rec.aWins : rec.bWins,
    awayWins: homeIsA ? rec.bWins : rec.aWins,
    draws: rec.draws,
    homeGoals: homeIsA ? rec.aGoals : rec.bGoals,
    awayGoals: homeIsA ? rec.bGoals : rec.aGoals,
    last: rec.last.map((m) => ({ date: m.date, home: m.home, away: m.away, homeScore: m.hs, awayScore: m.as })),
  };
}

export function buildPreview(num: number, state: TournamentState, model: ModelEngine): MatchPreview | null {
  const fixture = state.getFixture(num);
  if (!fixture) return null;

  const home = fixture.home.team;
  const away = fixture.away.team;
  const ext = getMatchExt<EspnSummary>(num);
  const summary = ext?.data;

  // map ESPN data by canonical team name (robust to home/away orientation)
  const espnFor = (team: string | null) => (team && summary ? summary.teams.find((t) => t.name === team) : undefined);
  const eh = espnFor(home);
  const ea = espnFor(away);

  const prediction = model.current().matches.find((m) => m.num === num) ?? null;

  return {
    num,
    fixture,
    venue: summary?.venue ?? fixture.venue,
    prediction,
    form: {
      home: eh ? summary!.form[eh.id] ?? [] : [],
      away: ea ? summary!.form[ea.id] ?? [] : [],
    },
    h2h: home && away ? h2hSummary(home, away) : null,
    lineups:
      eh && ea && (summary!.lineups[eh.id]?.length || summary!.lineups[ea.id]?.length)
        ? { home: summary!.lineups[eh.id] ?? [], away: summary!.lineups[ea.id] ?? [] }
        : null,
    keyPlayers: {
      home: home ? scorersData()[home] ?? [] : [],
      away: away ? scorersData()[away] ?? [] : [],
    },
    dataNote: !home || !away
      ? 'Knockout participants are decided once the bracket resolves.'
      : ext
        ? 'Live form, lineups and stats from ESPN; head-to-head and key players from 150 years of results.'
        : 'Head-to-head and key players from history; live form & lineups appear closer to kickoff.',
    updatedAt: ext?.updatedAt ?? null,
  };
}

export function buildTeamProfile(teamRaw: string, state: TournamentState, model: ModelEngine): TeamProfile | null {
  const snap = state.snapshot();
  const fixtures = snap.fixtures.filter((f) => f.home.team === teamRaw || f.away.team === teamRaw);
  if (!fixtures.length) return null;

  const group = fixtures.find((f) => f.group)?.group ?? null;
  const standing: StandingRow | null =
    group ? snap.tables[group]?.find((r) => r.team === teamRaw) ?? null : null;
  const odds = model.current().odds.find((o) => o.team === teamRaw) ?? null;

  return {
    team: teamRaw,
    elo: Math.round(ratingsData().ratings[teamRaw] ?? 1500),
    group,
    standing,
    fixtures,
    keyPlayers: scorersData()[teamRaw] ?? [],
    championOdds: odds?.champion ?? null,
    qualifyOdds: odds?.qualify ?? null,
  };
}
