import type { MatchLiveEvent } from '@/lib/types';

/**
 * Turns ESPN's flat commentary events into structured timeline items.
 * ESPN text is English prose with a stable shape per event type, e.g.
 *   "Goal! Korea Republic 1, Czechia 1. Hwang In-Beom (Korea Republic) right
 *    footed shot … Assisted by Lee Jae-Sung."
 *   "Substitution, Czechia. Adam Hlozek replaces Pavel Sulc."
 *   "Lee Gi-Hyuk (Korea Republic) is shown the yellow card for a bad foul."
 * Anything we can't parse keeps its raw text — never an empty card.
 */

export type EventKind = 'goal' | 'yellow' | 'red' | 'sub' | 'other';

export type EventDetail =
  | { type: 'assist'; name: string }
  | { type: 'penalty' }
  | { type: 'ownGoal' }
  | { type: 'raw'; text: string };

export interface ParsedEvent {
  kind: EventKind;
  side: 'home' | 'away' | null;
  minute: number | null;
  /** Scorer / booked player / incoming sub — or the raw text when unparseable. */
  title: string;
  detail: EventDetail | null;
  /** Running score after this event; goals only. */
  score: [number, number] | null;
  /** Outgoing player (substitutions). */
  subOut?: string;
}

/** Whole-match markers the timeline replaces with its own styled dividers. */
const MARKER_TYPES = new Set([
  'kickoff', 'halftime', 'start 2nd half', 'end regular time', 'end of game',
  'full time', 'match end', 'start 1st half',
]);

export function eventKind(type: string): EventKind {
  const t = type.toLowerCase();
  if (t.includes('goal') || t.includes('penalty - scored')) return 'goal';
  if (t.includes('yellow')) return 'yellow';
  if (t.includes('red')) return 'red';
  if (t.includes('substitution')) return 'sub';
  return 'other';
}

/** "… Korea Republic 1, Czechia 1." → [1, 1] (the score embedded in goal text). */
function parseScore(text: string): [number, number] | null {
  const m = /(\d+)\s*,[^.,\d]*?(\d+)\s*\./.exec(text);
  if (!m) return null;
  return [Number(m[1]), Number(m[2])];
}

function parseGoal(e: MatchLiveEvent, fallbackScore: [number, number] | null): Pick<ParsedEvent, 'title' | 'detail' | 'score'> {
  const text = e.text;
  const score = parseScore(text) ?? fallbackScore;
  const own = /Own Goal by ([^,.]+)/.exec(text);
  if (own?.[1]) return { title: own[1].trim(), detail: { type: 'ownGoal' }, score };
  // Scorer = first "Name (Team)" after the score sentence.
  const scorer = /\.\s*([^.()]+?)\s*\(/.exec(text);
  const title = scorer?.[1]?.trim() || text || e.type;
  let detail: EventDetail | null = null;
  const assist = /Assisted by ([^.]+?)(?:\s+(?:with|following|after)\b[^.]*)?\./.exec(text);
  if (assist?.[1]) detail = { type: 'assist', name: assist[1].trim() };
  else if (/penalty/i.test(text) || /penalty/i.test(e.type)) detail = { type: 'penalty' };
  return { title, detail, score };
}

function parseBooking(e: MatchLiveEvent): Pick<ParsedEvent, 'title' | 'detail'> {
  const m = /^([^(]+?)\s*\(/.exec(e.text);
  return { title: m?.[1]?.trim() || e.text || e.type, detail: null };
}

function parseSub(e: MatchLiveEvent): Pick<ParsedEvent, 'title' | 'detail' | 'subOut'> {
  const m = /\.\s*(.+?)\s+replaces\s+(.+?)\.?\s*$/.exec(e.text);
  if (m?.[1] && m[2]) return { title: m[1].trim(), detail: null, subOut: m[2].trim() };
  return { title: e.text || e.type, detail: null };
}

/**
 * Parse, de-noise and order events for display.
 * Drops whole-match markers (the component draws its own dividers) and the
 * empty-text duplicate rows ESPN emits for both teams on neutral events.
 */
export function parseEvents(events: MatchLiveEvent[]): ParsedEvent[] {
  const out: ParsedEvent[] = [];
  let running: [number, number] = [0, 0];
  for (const e of events) {
    const kind = eventKind(e.type);
    const type = e.type.toLowerCase();
    if (MARKER_TYPES.has(type)) continue;
    if (kind === 'other' && !e.text) continue; // duplicate/no-info rows
    let parsed: ParsedEvent;
    if (kind === 'goal') {
      // Fallback when the text carries no score: count by attributed side.
      const counted: [number, number] = e.team === 'away' ? [running[0], running[1] + 1] : [running[0] + 1, running[1]];
      const g = parseGoal(e, e.team ? counted : null);
      if (g.score) running = g.score;
      parsed = { kind, side: e.team, minute: e.minute, ...g };
    } else if (kind === 'yellow' || kind === 'red') {
      parsed = { kind, side: e.team, minute: e.minute, score: null, ...parseBooking(e) };
    } else if (kind === 'sub') {
      parsed = { kind, side: e.team, minute: e.minute, score: null, ...parseSub(e) };
    } else {
      // Neutral happenings (delays, VAR…) render centered regardless of team.
      parsed = { kind, side: null, minute: e.minute, title: e.text || e.type, detail: null, score: null };
    }
    out.push(parsed);
  }
  return out;
}

/** Goals only — feeds the Summary tab's key-moments card. */
export function goalEvents(events: MatchLiveEvent[]): ParsedEvent[] {
  return parseEvents(events).filter((e) => e.kind === 'goal');
}

/** Score at half-time: last goal score at minute ≤ 45 (0–0 when none). */
export function halfTimeScore(parsed: ParsedEvent[]): [number, number] {
  let ht: [number, number] = [0, 0];
  for (const e of parsed) {
    if (e.kind === 'goal' && e.score && e.minute != null && e.minute <= 45) ht = e.score;
  }
  return ht;
}
