import type { MatchFullStat } from '../../../src/lib/types'; // Pure normalizer for the FotMob matchDetails `stats` payload — no network or // DB, unit-testable in isolation (same pattern as statsNormalize). /** Curated full-time stats, in display order: FotMob key → our i18n key. * Unknown keys are dropped so the client's label dict stays exhaustive. */ const FULL_STAT_KEYS: [string, string][] = [ ['expected_goals', 'xg'], ['expected_goals_on_target', 'xgot'], ['big_chance', 'bigChances'], ['accurate_passes', 'accuratePasses'], ['long_balls_accurate', 'longBalls'], ['accurate_crosses', 'crosses'], ['touches_opp_box', 'touchesInBox'], ['corners', 'corners'], ['Offsides', 'offsides'], ['fouls', 'fouls'], ['matchstats.headers.tackles', 'tackles'], ['interceptions', 'interceptions'], ['shot_blocks', 'blocks'], ['clearances', 'clearances'], ['keeper_saves', 'saves'], ['duel_won', 'duelsWon'], ['ground_duels_won', 'groundDuels'], ['aerials_won', 'aerialDuels'], ['dribbles_succeeded', 'dribbles'], ]; interface RawStatEntry { key?: string; stats?: unknown[]; type?: string } interface RawStatGroup { stats?: RawStatEntry[] } /** matchDetails `stats`: Periods.{All,FirstHalf,SecondHalf}.stats = groups. */ export interface RawMatchStats { Periods?: { All?: { stats?: RawStatGroup[] } } } const usable = (v: unknown): v is string | number => (typeof v === 'number' && Number.isFinite(v)) || (typeof v === 'string' && v.trim() !== ''); /** Full-match stat rows from a raw FotMob `stats` payload. Any shape * surprise degrades to fewer rows (or none) — never a throw. */ export function normalizeMatchStats(raw: unknown): MatchFullStat[] { const groups = (raw as RawMatchStats | null | undefined)?.Periods?.All?.stats; if (!Array.isArray(groups)) return []; // Categories repeat across groups ("Top stats" previews the rest) — first // occurrence wins, output follows the whitelist order. const seen = new Map(); for (const g of groups) { if (!g || !Array.isArray(g.stats)) continue; for (const s of g.stats) { if (!s || typeof s.key !== 'string' || s.type === 'title' || !Array.isArray(s.stats)) continue; const [h, a] = s.stats; if (!usable(h) || !usable(a) || seen.has(s.key)) continue; seen.set(s.key, { home: String(h), away: String(a) }); } } const out: MatchFullStat[] = []; for (const [fmKey, key] of FULL_STAT_KEYS) { const v = seen.get(fmKey); if (v) out.push({ key, ...v }); } return out; }