export interface EspnPlayerStatMatch {
  playerExternalId: string;
  playerName: string;
  team: string | null;
  opponent: string | null;
  value: number;
}

type StatSpec =
  | { kind: 'direct'; key: string }
  | { kind: 'compoundFirst'; key: string }
  | { kind: 'sum'; keys: [string, string] }
  | { kind: 'mlbOuts'; key: string };

function stripSuffixTokens(value: string): string {
  return value.replace(/\b(jr|sr|ii|iii|iv|v)\b$/i, '').trim();
}

export function normalizeResolverPlayerName(value: string | null | undefined): string {
  return stripSuffixTokens(
    (value || '')
      .normalize('NFD')
      .replace(/[\u0300-\u036f]/g, '')
      .toLowerCase()
      .replace(/&/g, 'and')
      .replace(/[^a-z0-9]+/g, ' ')
      .trim(),
  ).replace(/\s+/g, ' ');
}

function namesMatch(target: string | null | undefined, candidate: string | null | undefined): boolean {
  const left = normalizeResolverPlayerName(target);
  const right = normalizeResolverPlayerName(candidate);
  if (!left || !right) return false;
  return left === right;
}

function parseNumericStat(value: unknown): number | null {
  if (value == null || value === '') return null;
  const parsed = typeof value === 'number' ? value : parseFloat(String(value));
  return Number.isFinite(parsed) ? parsed : null;
}

function parseCompoundLeadingNumber(value: unknown): number | null {
  const raw = String(value ?? '').trim();
  if (!raw) return null;
  const [first] = raw.split('-');
  return parseNumericStat(first);
}

function parseMlbPitchingOuts(value: unknown): number | null {
  const raw = String(value ?? '').trim();
  if (!raw) return null;
  const match = raw.match(/^(\d+)\.(\d)$/);
  if (!match) return parseNumericStat(raw);

  const fullInnings = parseInt(match[1], 10);
  const partialOuts = parseInt(match[2], 10);
  if (!Number.isFinite(fullInnings) || !Number.isFinite(partialOuts)) return null;
  if (partialOuts < 0 || partialOuts > 2) return null;
  return (fullInnings * 3) + partialOuts;
}

function resolveStatSpec(league: string | null | undefined, statKey: string | null | undefined): StatSpec | null {
  const safeLeague = (league || '').trim().toLowerCase();
  const safeStat = (statKey || '').trim();

  if (safeLeague === 'nba' || safeLeague === 'ncaab') {
    if (safeStat === 'points') return { kind: 'direct', key: 'points' };
    if (safeStat === 'assists') return { kind: 'direct', key: 'assists' };
    if (safeStat === 'rebounds') return { kind: 'direct', key: 'rebounds' };
    if (safeStat === 'threePointersMade') return { kind: 'compoundFirst', key: 'threePointFieldGoalsMade-threePointFieldGoalsAttempted' };
    return null;
  }

  if (safeLeague === 'nhl') {
    if (safeStat === 'points') return { kind: 'sum', keys: ['goals', 'assists'] };
    if (safeStat === 'assists') return { kind: 'direct', key: 'assists' };
    if (safeStat === 'goals') return { kind: 'direct', key: 'goals' };
    if (safeStat === 'shots' || safeStat === 'shots_on_goal' || safeStat === 'shotsOnGoal') return { kind: 'direct', key: 'shotsTotal' };
    if (safeStat === 'saves') return { kind: 'direct', key: 'saves' };
    return null;
  }

  if (safeLeague === 'mlb') {
    if (safeStat === 'batting_RBI') return { kind: 'direct', key: 'RBIs' };
    if (safeStat === 'batting_homeRuns') return { kind: 'direct', key: 'homeRuns' };
    if (safeStat === 'batting_basesOnBalls') return { kind: 'direct', key: 'walks' };
    if (safeStat === 'batting_totalBases') return { kind: 'direct', key: 'totalBases' };
    if (safeStat === 'batting_stolenBases' || safeStat === 'stolenBases') return { kind: 'direct', key: 'stolenBases' };
    if (safeStat === 'pitching_outs') return { kind: 'mlbOuts', key: 'fullInnings.partInnings' };
    if (safeStat === 'pitching_hits') return { kind: 'direct', key: 'hits' };
    if (safeStat === 'pitching_basesOnBalls') return { kind: 'direct', key: 'walks' };
    if (safeStat === 'pitching_earnedRuns') return { kind: 'direct', key: 'earnedRuns' };
    if (safeStat === 'pitching_strikeouts') return { kind: 'direct', key: 'strikeouts' };
    return null;
  }

  return null;
}

export function supportsEspnPlayerStat(league: string | null | undefined, statKey: string | null | undefined): boolean {
  return resolveStatSpec(league, statKey) != null;
}

function resolveOpponent(summary: any, matchedTeam: string | null): string | null {
  const competitors = summary?.header?.competitions?.[0]?.competitors;
  if (!Array.isArray(competitors) || !matchedTeam) return null;

  const other = competitors.find((entry: any) => {
    const displayName = entry?.team?.displayName || entry?.team?.name || null;
    return !namesMatch(displayName, matchedTeam);
  });

  return other?.team?.displayName || other?.team?.name || null;
}

function lookupDirectStat(keys: string[], stats: any[], key: string): number | null {
  const idx = keys.indexOf(key);
  if (idx === -1) return null;
  return parseNumericStat(stats[idx]);
}

export function extractEspnPlayerStat(
  summary: any,
  league: string | null | undefined,
  playerName: string | null | undefined,
  statKey: string | null | undefined,
): EspnPlayerStatMatch | null {
  const spec = resolveStatSpec(league, statKey);
  if (!spec) return null;

  const teams = Array.isArray(summary?.boxscore?.players) ? summary.boxscore.players : [];
  for (const teamBox of teams) {
    const teamName = teamBox?.team?.displayName || teamBox?.team?.name || null;
    const opponent = resolveOpponent(summary, teamName);
    const groups = Array.isArray(teamBox?.statistics) ? teamBox.statistics : [];

    for (const group of groups) {
      const keys = Array.isArray(group?.keys) ? group.keys.map((entry: any) => String(entry)) : [];
      const athletes = Array.isArray(group?.athletes) ? group.athletes : [];

      for (const athleteRow of athletes) {
        const athlete = athleteRow?.athlete;
        const displayName = athlete?.displayName || athlete?.fullName || athlete?.name || null;
        if (!namesMatch(playerName, displayName)) continue;

        const stats = Array.isArray(athleteRow?.stats) ? athleteRow.stats : [];
        let value: number | null = null;

        if (spec.kind === 'direct') {
          value = lookupDirectStat(keys, stats, spec.key);
        } else if (spec.kind === 'compoundFirst') {
          const idx = keys.indexOf(spec.key);
          value = idx === -1 ? null : parseCompoundLeadingNumber(stats[idx]);
        } else if (spec.kind === 'sum') {
          const left = lookupDirectStat(keys, stats, spec.keys[0]);
          const right = lookupDirectStat(keys, stats, spec.keys[1]);
          value = left != null && right != null ? left + right : null;
        } else if (spec.kind === 'mlbOuts') {
          const idx = keys.indexOf(spec.key);
          value = idx === -1 ? null : parseMlbPitchingOuts(stats[idx]);
        }

        if (value == null) continue;

        return {
          playerExternalId: String(athlete?.id || displayName || ''),
          playerName: String(displayName || playerName || ''),
          team: teamName,
          opponent,
          value,
        };
      }
    }
  }

  return null;
}
