import { useEffect, useMemo, useState } from 'react';
import { Link, useParams } from '@tanstack/react-router';
import { ArrowLeft, ArrowRight, Shield, Shirt } from 'lucide-react';
import { Badge } from '@/components/ui/Badge';
import { Card, CardBody, CardHeader } from '@/components/ui/Card';
import { WinProbBar } from '@/components/WinProbBar';
import { WinProbTimeline, type TimelinePoint } from '@/components/WinProbTimeline';
import { OddsMovement } from '@/components/OddsMovement';
import { FormChips } from '@/components/FormChips';
import { XgRace } from '@/components/XgRace';
import { ShotMap } from '@/components/ShotMap';
import { MomentumStrip } from '@/components/MomentumStrip';
import { EventIcon, MatchTimeline } from '@/components/MatchTimeline';
import { LineupPitch } from '@/components/LineupPitch';
import { teamFlag } from '@/lib/teams';
import { fmt, useFormat, useT } from '@/lib/i18n';
import { goalEvents } from '@/lib/matchEvents';
import { inPlayProbs } from '@/lib/model/inplay';
import { useTournamentStore } from '@/stores/tournamentStore';
import type { Fixture, KeyPlayer, MatchPreview, MatchRich, OddsPoint } from '@/lib/types';

const num = (s: string | undefined) => (s ? Number(s.replace('%', '')) || 0 : 0);

type TabKey = 'summary' | 'timeline' | 'stats' | 'lineups';

function LiveStatRow({ label, home, away }: { label: string; home: number; away: number }) {
  const total = home + away || 1;
  return (
    <div>
      <div className="flex items-center justify-between text-sm">
        <span className="tnum font-bold text-accent">{home}</span>
        <span className="text-xs uppercase tracking-wide text-faint">{label}</span>
        <span className="tnum font-bold text-info">{away}</span>
      </div>
      <div className="mt-1 flex h-1.5 overflow-hidden rounded-full bg-elevated">
        <div className="bg-accent" style={{ width: `${(home / total) * 100}%` }} />
        <div className="ml-auto bg-info" style={{ width: `${(away / total) * 100}%` }} />
      </div>
    </div>
  );
}

function ScorerList({ team, players }: { team: string; players: KeyPlayer[] }) {
  const t = useT();
  return (
    <div>
      <div className="mb-2 flex items-center gap-2 text-sm font-semibold text-ink"><span aria-hidden>{teamFlag(team)}</span> {team}</div>
      {players.length ? (
        <ul className="space-y-1">
          {players.slice(0, 6).map((p) => (
            <li key={p.name} className="flex items-center justify-between text-sm">
              <span className="truncate text-ink-soft">{p.name}</span>
              <span className="tnum shrink-0 text-faint">{p.goals}{p.pens ? ` (${fmt(t.common.pensShort, { n: p.pens })})` : ''}</span>
            </li>
          ))}
        </ul>
      ) : <p className="text-xs text-faint">{t.common.noData}</p>}
    </div>
  );
}

function LineupCol({ team, players }: { team: string; players: { name: string; position: string | null; number: number | null; starter: boolean }[] }) {
  const starters = players.filter((p) => p.starter);
  const list = starters.length ? starters : players;
  return (
    <div>
      <div className="mb-2 text-sm font-semibold text-ink">{team}</div>
      <ul className="space-y-0.5 text-sm">
        {list.map((p) => (
          <li key={p.name} className="flex items-center gap-2 text-ink-soft">
            <span className="tnum w-5 text-right text-xs text-faint">{p.number ?? ''}</span>
            <span className="truncate">{p.name}</span>
            <span className="ml-auto text-[11px] text-faint">{p.position}</span>
          </li>
        ))}
      </ul>
    </div>
  );
}

/** Hero stat chip: faint label · mono value. */
function HeroChip({ label, value, gold }: { label: string; value: string; gold?: boolean }) {
  return (
    <span className="inline-flex max-w-full items-center gap-1.5 rounded-full bg-elevated px-3 py-1 text-xs">
      <span className="shrink-0 text-faint">{label}</span>
      <span className={`tnum truncate ${gold ? 'text-gold' : 'text-ink-soft'}`}>{value}</span>
    </span>
  );
}

export function MatchPreviewPage() {
  const { num: numParam } = useParams({ strict: false }) as { num: string };
  const { t, locale, kickoffDay, kickoffTime } = useFormat();
  const [preview, setPreview] = useState<MatchPreview | null>(null);
  const [timeline, setTimeline] = useState<TimelinePoint[]>([]);
  const [oddsHistory, setOddsHistory] = useState<OddsPoint[]>([]);
  const [rich, setRich] = useState<MatchRich | null>(null);
  const [failed, setFailed] = useState(false);
  const [activeTab, setActiveTab] = useState<TabKey>('summary');

  // Live score/minute arrive over the WebSocket snapshot — overlay them on the
  // (less-frequently-fetched) preview.
  const liveFixture = useTournamentStore((s) => s.snapshot?.fixtures.find((f) => f.num === Number(numParam)));
  const isLive = (liveFixture?.status ?? preview?.fixture.status) === 'live';

  useEffect(() => {
    let alive = true;
    setPreview(null);
    setTimeline([]);
    setRich(null);
    setFailed(false);
    setActiveTab('summary');
    const load = () =>
      fetch(`/api/preview/${numParam}`)
        .then((r) => (r.ok ? r.json() : Promise.reject()))
        .then((d: MatchPreview) => alive && setPreview(d))
        .catch(() => alive && setFailed(true));
    const loadTimeline = () =>
      fetch(`/api/inplay/${numParam}`)
        .then((r) => (r.ok ? r.json() : Promise.reject()))
        .then((d: { points: TimelinePoint[] }) => alive && setTimeline(d.points))
        .catch(() => {});
    const loadRich = () =>
      fetch(`/api/match-rich/${numParam}`)
        .then((r) => (r.ok ? r.json() : Promise.reject()))
        .then((d: MatchRich) => alive && setRich(d))
        .catch(() => {});
    void load();
    void loadTimeline();
    void loadRich();
    // line history changes on a 3h sweep — once per visit is plenty
    fetch(`/api/odds/${numParam}`)
      .then((r) => (r.ok ? r.json() : Promise.reject()))
      .then((d: { history: OddsPoint[] }) => alive && setOddsHistory(d.history))
      .catch(() => {});
    const id = setInterval(() => {
      if (useTournamentStore.getState().snapshot?.fixtures.find((f) => f.num === Number(numParam))?.status === 'live') {
        void load();
        void loadTimeline();
        void loadRich();
      }
    }, 10_000);
    return () => { alive = false; clearInterval(id); };
  }, [numParam]);

  const f: Fixture | undefined = liveFixture ?? preview?.fixture;

  const inPlay = useMemo(() => {
    if (!preview?.prediction || !f || f.status !== 'live' || f.homeScore == null || f.awayScore == null) return null;
    return inPlayProbs(preview.prediction.lambdaHome, preview.prediction.lambdaAway, f.minute ?? 0, f.homeScore, f.awayScore);
  }, [preview, f]);

  const statRows = useMemo<[string, string][]>(() => [
    ['possessionPct', t.match.stats.possessionPct],
    ['totalShots', t.match.stats.totalShots],
    ['shotsOnTarget', t.match.stats.shotsOnTarget],
    ['wonCorners', t.match.stats.wonCorners],
    ['foulsCommitted', t.match.stats.foulsCommitted],
    ['saves', t.match.stats.saves],
  ], [t]);

  const goals = useMemo(() => (preview ? goalEvents(preview.events) : []), [preview]);

  if (failed) return <div className="py-16 text-center text-muted">{t.match.loadError} <Link to="/" className="text-accent">{t.match.backToLive}</Link></div>;
  if (!preview || !f) return <div className="h-96 animate-pulse rounded-2xl border border-line bg-panel" />;

  const hasScore = f.status === 'live' || f.status === 'finished';
  const homeName = f.home.label;
  const awayName = f.away.label;
  const finished = f.status === 'finished';
  const koT = new Date(f.kickoff).getTime();
  const hasOddsChart = oddsHistory.filter((o) => o.home_ml != null && o.draw_ml != null && o.away_ml != null && o.captured_at <= koT).length >= 2;

  // Hero extras from the rich capture: kickoff-hour weather (pre-match only)
  // and post-match official chips (attendance, referee, player of the match).
  const wx = f.status === 'scheduled' ? rich?.weather : null;
  const weatherText = wx && wx.tempC != null && wx.precipProbPct != null && wx.windKmh != null
    ? fmt(t.match.weatherLine, { temp: Math.round(wx.tempC), precip: Math.round(wx.precipProbPct), wind: Math.round(wx.windKmh) })
    : null;
  const altitudeM = wx && wx.elevationM >= 1000 ? Math.round(wx.elevationM) : null;
  const infoText = rich?.info && rich.info.stadium && rich.info.attendance != null && rich.info.referee && f.status === 'scheduled'
    ? fmt(t.match.attendanceLine, { stadium: rich.info.stadium, n: rich.info.attendance.toLocaleString(locale), ref: rich.info.referee })
    : null;

  const heroChips: { label: string; value: string; gold?: boolean }[] = [];
  if (hasScore) {
    if (rich?.xg) heroChips.push({ label: 'xG', value: `${rich.xg.home.toFixed(2)}–${rich.xg.away.toFixed(2)}` });
    if (isLive && preview.liveStats) {
      const ls = preview.liveStats;
      if (ls.home.possessionPct != null || ls.away.possessionPct != null) {
        heroChips.push({ label: t.match.chips.poss, value: `${num(ls.home.possessionPct)}%–${num(ls.away.possessionPct)}%` });
      }
      if (ls.home.totalShots != null || ls.away.totalShots != null) {
        heroChips.push({ label: t.match.chips.shots, value: `${num(ls.home.totalShots)}–${num(ls.away.totalShots)}` });
      }
    }
    if (finished) {
      if (rich?.potm) heroChips.push({ label: t.match.potm, value: rich.potm.rating != null ? `${rich.potm.name} · ${rich.potm.rating}` : rich.potm.name, gold: true });
      if (rich?.info?.attendance != null) heroChips.push({ label: t.match.chips.att, value: rich.info.attendance.toLocaleString(locale) });
      if (rich?.info?.referee) heroChips.push({ label: t.match.chips.ref, value: rich.info.referee });
    }
  }

  // Tabs only appear when their data exists (e.g. no Timeline before kickoff).
  const tabs: TabKey[] = ['summary'];
  if (preview.events.length > 0) tabs.push('timeline');
  if (preview.liveStats || (rich && (rich.shots.length >= 3 || rich.momentum.length >= 10))) tabs.push('stats');
  tabs.push('lineups');
  const tab: TabKey = tabs.includes(activeTab) ? activeTab : 'summary';

  const modelCard = preview.prediction && (
    <Card>
      <CardHeader><span className="font-display font-bold text-ink">{hasScore ? t.match.preMatchModel : t.match.modelExpectation}</span></CardHeader>
      <CardBody className="space-y-2">
        <WinProbBar home={preview.prediction.home} away={preview.prediction.away} probs={preview.prediction.probs} topScore={preview.prediction.topScore} />
        <p className="text-xs text-faint">{fmt(t.match.expectedGoalsLine, { home: preview.prediction.lambdaHome.toFixed(2), away: preview.prediction.lambdaAway.toFixed(2) })}</p>
      </CardBody>
    </Card>
  );

  return (
    <div className="space-y-5">
      <Link to="/" className="inline-flex items-center gap-1.5 text-sm text-muted hover:text-ink"><ArrowLeft size={15} /> {t.common.back}</Link>

      {/* hero scoreboard */}
      <div className={`relative overflow-hidden rounded-2xl border bg-gradient-to-b from-panel to-surface p-6 md:p-8 ${isLive ? 'border-live/40 ring-1 ring-live/30' : 'border-line'}`}>
        <div aria-hidden className="pointer-events-none absolute inset-0 bg-[radial-gradient(120%_90%_at_50%_-20%,var(--app-accent-glow),transparent_60%)]" />
        <div className="relative">
          <div className="smallcaps text-center">
            {f.group ? fmt(t.common.group, { group: f.group }) : t.stage[f.stage]}
            <span className="text-line-strong"> · </span>{kickoffDay(f.kickoff)}
            <span className="text-line-strong"> · </span>{kickoffTime(f.kickoff)}
            <span className="text-line-strong"> · </span>{preview.venue}
          </div>
          <div className="mt-5 grid grid-cols-[1fr_auto_1fr] items-center gap-2 md:gap-6">
            <Link to="/team/$name" params={{ name: f.home.team ?? '' }} className="flex flex-col items-center gap-1.5 hover:opacity-80">
              <span aria-hidden className="text-4xl md:text-6xl">{f.home.team ? teamFlag(f.home.team) : <Shield size={40} className="text-faint" />}</span>
              <span className="text-center text-[15px] font-bold text-ink md:text-lg">{homeName}</span>
            </Link>
            <div className="text-center">
              {hasScore ? (
                <div className="tnum text-[40px] font-semibold leading-none tracking-[-0.04em] text-ink md:text-6xl">
                  {f.homeScore ?? 0}<span className="text-[0.5em] text-line-strong">–</span>{f.awayScore ?? 0}
                </div>
              ) : (
                <div className="tnum text-2xl font-bold text-muted md:text-3xl">{kickoffTime(f.kickoff)}</div>
              )}
              {isLive && <div className="mt-2 inline-flex items-center gap-1.5 text-[11px] font-bold uppercase text-live"><span className="live-dot h-1.5 w-1.5 rounded-full bg-live" />{f.minute ? fmt(t.live.minute, { n: f.minute }) : t.common.liveNow}</div>}
              {finished && <div className="mt-2 text-[11px] font-bold uppercase tracking-wider text-faint">{t.common.fullTime}</div>}
            </div>
            <Link to="/team/$name" params={{ name: f.away.team ?? '' }} className="flex flex-col items-center gap-1.5 hover:opacity-80">
              <span aria-hidden className="text-4xl md:text-6xl">{f.away.team ? teamFlag(f.away.team) : <Shield size={40} className="text-faint" />}</span>
              <span className="text-center text-[15px] font-bold text-ink md:text-lg">{awayName}</span>
            </Link>
          </div>
          {heroChips.length > 0 && (
            <div className="mt-5 flex flex-wrap items-center justify-center gap-2 border-t border-line pt-4">
              {heroChips.map((c) => <HeroChip key={c.label} label={c.label} value={c.value} gold={c.gold ?? false} />)}
            </div>
          )}
          {(weatherText || infoText) && (
            <div className="mt-5 space-y-1 border-t border-line pt-3 text-center text-xs text-muted">
              {weatherText && (
                <div className="flex flex-wrap items-center justify-center gap-2">
                  <span>{weatherText}</span>
                  {altitudeM != null && <Badge tone="muted">{fmt(t.match.altitude, { m: altitudeM })}</Badge>}
                </div>
              )}
              {infoText && <div>{infoText}</div>}
            </div>
          )}
        </div>
      </div>

      {/* sticky sub-nav */}
      <div className="sticky top-14 z-20 bg-surface/90 py-1 backdrop-blur">
        <div className="flex gap-1 overflow-x-auto rounded-xl border border-line bg-panel p-1" role="tablist">
          {tabs.map((k) => (
            <button
              key={k}
              role="tab"
              aria-selected={tab === k}
              onClick={() => setActiveTab(k)}
              className={`flex-1 whitespace-nowrap rounded-lg px-3 py-2 text-sm font-semibold transition-colors ${tab === k ? 'bg-panel-2 text-ink shadow-sm' : 'text-muted hover:text-ink-soft'}`}
            >
              {t.match.tabs[k]}
            </button>
          ))}
        </div>
      </div>

      {/* ── Summary ── */}
      {tab === 'summary' && (
        <div className="space-y-4">
          <div className="grid items-start gap-4 md:grid-cols-2">
            {inPlay && preview.prediction ? (
              <Card className="border-live/30">
                <CardHeader className="flex items-center gap-2">
                  <span className="live-dot h-2 w-2 rounded-full bg-live" />
                  <span className="font-display font-bold text-ink">{t.match.liveWinProbability}</span>
                </CardHeader>
                <CardBody>
                  <WinProbBar home={homeName} away={awayName} probs={inPlay} />
                  {timeline.length >= 2 && (
                    <div className="mt-4">
                      <WinProbTimeline points={timeline} home={homeName} away={awayName} />
                    </div>
                  )}
                  <p className="mt-2 text-xs text-faint">{t.match.inPlayHelp}</p>
                </CardBody>
              </Card>
            ) : modelCard}
            {preview.events.length > 0 && (
              <Card>
                <CardHeader><span className="font-display font-bold text-ink">{t.match.keyMoments}</span></CardHeader>
                <CardBody>
                  {goals.length ? (
                    <div className="space-y-2.5">
                      {goals.map((g, i) => (
                        <div key={i} className="flex items-center gap-2 text-sm">
                          <span className="tnum w-8 shrink-0 text-xs text-faint">{g.minute != null ? fmt(t.live.minute, { n: g.minute }) : ''}</span>
                          <span aria-hidden className={`h-1.5 w-1.5 shrink-0 rounded-full ${g.side === 'away' ? 'bg-info' : 'bg-accent'}`} />
                          <EventIcon kind="goal" />
                          <span className="truncate font-medium text-ink-soft">{g.title}</span>
                          {g.score && <span className="tnum ml-auto shrink-0 text-xs text-faint">{g.score[0]}–{g.score[1]}</span>}
                        </div>
                      ))}
                    </div>
                  ) : (
                    <p className="text-sm text-faint">{t.match.noGoalsYet}</p>
                  )}
                  <button onClick={() => setActiveTab('timeline')} className="mt-3 inline-flex items-center gap-1 text-sm font-semibold text-accent hover:underline">
                    {t.match.viewTimeline} <ArrowRight size={14} />
                  </button>
                </CardBody>
              </Card>
            )}
          </div>
          {/* live matches keep the pre-match view alongside the in-play one */}
          {inPlay && preview.prediction && modelCard}
          {finished && timeline.length >= 2 && (
            <Card>
              <CardHeader><span className="font-display font-bold text-ink">{t.match.momentum}</span></CardHeader>
              <CardBody>
                <WinProbTimeline points={timeline} home={homeName} away={awayName} />
              </CardBody>
            </Card>
          )}
          {preview.prediction && hasOddsChart && (
            <Card>
              <CardHeader><span className="font-display font-bold text-ink">{t.match.oddsMovement}</span></CardHeader>
              <CardBody>
                <OddsMovement history={oddsHistory} model={preview.prediction.probs} kickoff={f.kickoff} />
              </CardBody>
            </Card>
          )}
        </div>
      )}

      {/* ── Timeline ── */}
      {tab === 'timeline' && preview.events.length > 0 && (
        <Card>
          <CardBody className="px-2 sm:px-4">
            <MatchTimeline events={preview.events} status={f.status} minute={f.minute} homeScore={f.homeScore} awayScore={f.awayScore} />
          </CardBody>
        </Card>
      )}

      {/* ── Stats ── */}
      {tab === 'stats' && (
        <div className="grid items-start gap-4 md:grid-cols-2">
          {preview.liveStats && (
            <Card>
              <CardHeader><span className="font-display font-bold text-ink">{t.match.statsTitle}</span></CardHeader>
              <CardBody className="space-y-3">
                {statRows.filter(([k]) => preview.liveStats!.home[k] != null || preview.liveStats!.away[k] != null).map(([k, label]) => (
                  <LiveStatRow key={k} label={label} home={num(preview.liveStats!.home[k])} away={num(preview.liveStats!.away[k])} />
                ))}
              </CardBody>
            </Card>
          )}
          {rich && rich.momentum.length >= 10 && (
            <Card>
              <CardHeader><span className="font-display font-bold text-ink">{t.match.momentumTitle}</span></CardHeader>
              <CardBody>
                <MomentumStrip points={rich.momentum} home={homeName} away={awayName} />
              </CardBody>
            </Card>
          )}
          {rich && rich.shots.length >= 3 && (
            <>
              <Card>
                <CardHeader className="flex items-center justify-between">
                  <span className="font-display font-bold text-ink">{t.match.xgRace}</span>
                  {rich.xg && (
                    <span className="tnum text-sm font-bold">
                      <span className="text-accent">{rich.xg.home.toFixed(2)}</span>
                      <span className="font-normal text-faint"> – </span>
                      <span className="text-info">{rich.xg.away.toFixed(2)}</span>
                    </span>
                  )}
                </CardHeader>
                <CardBody>
                  <XgRace shots={rich.shots} home={homeName} away={awayName} />
                </CardBody>
              </Card>
              <Card>
                <CardHeader><span className="font-display font-bold text-ink">{t.match.shotMap}</span></CardHeader>
                <CardBody>
                  <ShotMap shots={rich.shots} home={homeName} away={awayName} />
                  <p className="mt-2 text-xs text-faint">{t.match.xgAttribution}</p>
                </CardBody>
              </Card>
            </>
          )}
        </div>
      )}

      {/* ── Lineups ── */}
      {tab === 'lineups' && (
        <div className="space-y-4">
          {/* FotMob serves predicted XIs before kickoff — only draw the pitch
              once the match has started or ESPN confirms the lineups. */}
          {rich?.lineup && (hasScore || preview.lineups) ? (
            <Card>
              <CardHeader className="flex items-center gap-2"><Shirt size={16} className="text-accent" /><span className="font-display font-bold text-ink">{t.match.lineups}</span></CardHeader>
              <CardBody>
                <LineupPitch lineup={rich.lineup} home={homeName} away={awayName} events={preview.events} />
                <p className="mt-2 text-xs text-faint">{t.match.xgAttribution}</p>
              </CardBody>
            </Card>
          ) : (
            <Card>
              <CardHeader className="flex items-center gap-2"><Shirt size={16} className="text-accent" /><span className="font-display font-bold text-ink">{preview.lineups ? t.match.lineups : t.match.keyPlayers}</span></CardHeader>
              <CardBody className="grid grid-cols-2 gap-6">
                {preview.lineups ? (
                  <><LineupCol team={homeName} players={preview.lineups.home} /><LineupCol team={awayName} players={preview.lineups.away} /></>
                ) : (
                  <><ScorerList team={homeName} players={preview.keyPlayers.home} /><ScorerList team={awayName} players={preview.keyPlayers.away} /></>
                )}
              </CardBody>
            </Card>
          )}
          <div className="grid items-start gap-4 md:grid-cols-2">
            {(preview.form.home.length > 0 || preview.form.away.length > 0) && (
              <Card>
                <CardHeader><span className="font-display font-bold text-ink">{t.match.recentForm}</span></CardHeader>
                <CardBody className="space-y-3">
                  <div className="flex items-center justify-between"><span className="flex items-center gap-2 text-sm font-medium text-ink">{f.home.team && teamFlag(f.home.team)} {homeName}</span><FormChips form={preview.form.home} /></div>
                  <div className="flex items-center justify-between"><span className="flex items-center gap-2 text-sm font-medium text-ink">{f.away.team && teamFlag(f.away.team)} {awayName}</span><FormChips form={preview.form.away} /></div>
                </CardBody>
              </Card>
            )}
            {preview.h2h && (
              <Card>
                <CardHeader><span className="font-display font-bold text-ink">{t.match.headToHead}</span></CardHeader>
                <CardBody>
                  <div className="mb-3 grid grid-cols-3 items-center text-center">
                    <div><div className="tnum text-2xl font-extrabold text-accent">{preview.h2h.homeWins}</div><div className="text-[11px] text-faint">{fmt(t.match.h2h.teamWins, { team: homeName })}</div></div>
                    <div><div className="tnum text-2xl font-extrabold text-muted">{preview.h2h.draws}</div><div className="text-[11px] text-faint">{fmt(t.match.h2h.drawsTotal, { games: preview.h2h.games })}</div></div>
                    <div><div className="tnum text-2xl font-extrabold text-info">{preview.h2h.awayWins}</div><div className="text-[11px] text-faint">{fmt(t.match.h2h.teamWins, { team: awayName })}</div></div>
                  </div>
                  <div className="border-t border-line pt-2">
                    <div className="mb-1 text-[11px] uppercase tracking-wide text-faint">{t.match.h2h.recentMeetings}</div>
                    <ul className="space-y-1 text-sm">
                      {preview.h2h.last.map((m, i) => (
                        <li key={i} className="flex items-center justify-between text-ink-soft"><span className="text-faint">{m.date.slice(0, 10)}</span><span>{m.home} <span className="tnum font-semibold text-ink">{m.homeScore}–{m.awayScore}</span> {m.away}</span></li>
                      ))}
                    </ul>
                  </div>
                </CardBody>
              </Card>
            )}
          </div>
        </div>
      )}

      <p className="text-center text-xs text-faint">{preview.dataNote}</p>
    </div>
  );
}
