import { useEffect, useMemo, useState, type ReactNode } from 'react';
import { Link } from '@tanstack/react-router';
import { Wand2 } from 'lucide-react';
import { PageHeader } from '@/components/ui/PageHeader';
import { useTournamentStore } from '@/stores/tournamentStore';
import { teamFlag } from '@/lib/teams';
import { cn } from '@/lib/cn';
import { fmt, useFormat, useT } from '@/lib/i18n';
import { hostAdvantage } from '@/lib/model/hosts';
import { knockoutAdvanceProb, predictMatch, type RatingsModel } from '@/lib/model/predict';
import { championPath, effectiveBracket, prunePicks, type EffMatch, type Picks, type PickSide } from '@/lib/whatif';
import type { Fixture, MatchProbs, Stage, TeamSlot } from '@/lib/types';

type KnockoutStage = (typeof COLUMN_STAGES)[number];

const COLUMN_STAGES = ['r32', 'r16', 'qf', 'sf', 'final'] as const;

/** A knockout card in what-if mode: tap a side to send that team through. */
function WhatIfMatch({ f, eff, pick, advHome, onPick, wide = false }: {
  f: Fixture;
  eff: EffMatch;
  pick: PickSide | undefined;
  /** model probability the home side advances (null while ratings load / slots open) */
  advHome: number | null;
  onPick: (side: PickSide) => void;
  wide?: boolean;
}) {
  const { t } = useFormat();
  const side = (s: PickSide, team: string | null, label: string): ReactNode => {
    const picked = pick === s || (eff.decided && eff.winner != null && team === eff.winner);
    const adv = advHome == null ? null : Math.round((s === 'home' ? advHome : 1 - advHome) * 100);
    return (
      <button
        type="button"
        disabled={eff.decided || !team}
        onClick={() => onPick(s)}
        className={cn(
          'flex w-full items-center justify-between gap-2 px-2.5 py-1.5 text-left',
          !eff.decided && team && 'hover:bg-elevated',
          picked && 'bg-accent-glow font-bold',
        )}
      >
        <span className="flex min-w-0 items-center gap-1.5">
          {team ? (
            <>
              <span aria-hidden className="text-sm leading-none">{teamFlag(team)}</span>
              <span className={cn('truncate', picked ? 'text-accent' : 'text-ink')}>{team}</span>
            </>
          ) : (
            <span className="truncate text-xs italic text-faint">{label}</span>
          )}
        </span>
        {team && adv != null && !eff.decided && <span className="tnum shrink-0 text-[11px] text-faint">{adv}%</span>}
      </button>
    );
  };
  return (
    <div className={cn('overflow-hidden rounded-lg border bg-panel text-sm', pick ? 'border-accent/40' : 'border-line', wide ? 'w-full' : 'w-52')}>
      {side('home', eff.home, f.home.label)}
      <div className="h-px bg-line" />
      {side('away', eff.away, f.away.label)}
      <div className="border-t border-line bg-surface-2 px-2.5 py-1 text-[11px] text-faint">
        {fmt(t.common.matchNumberShort, { num: f.num })}{eff.decided ? ` · ${t.common.fullTimeShort}` : ''}
      </div>
    </div>
  );
}

function Side({ slot, score, winner }: { slot: TeamSlot; score: number | null; winner: boolean }) {
  return (
    <div className={cn('flex items-center justify-between gap-2 px-2.5 py-1.5', winner && 'font-bold')}>
      <span className="flex min-w-0 items-center gap-1.5">
        {slot.team ? (
          <>
            <span aria-hidden className="text-sm leading-none">{teamFlag(slot.team)}</span>
            <span className="truncate text-ink">{slot.team}</span>
          </>
        ) : (
          <span className="truncate text-xs italic text-faint" title={slot.label}>{slot.label}</span>
        )}
      </span>
      {score !== null && <span className="tnum shrink-0 text-ink">{score}</span>}
    </div>
  );
}

function AdvanceBar({ probs }: { probs: MatchProbs }) {
  const t = useT();
  // Advance probability = regulation win + half of draws (shootout ≈ coin flip).
  const home = Math.round((probs.home + probs.draw / 2) * 100);
  return (
    <div className="flex items-center gap-1.5 border-t border-line px-2.5 py-1" title={t.bracket.advanceTooltip}>
      <span className="tnum w-7 text-[10px] text-accent">{home}%</span>
      <div className="flex h-1.5 flex-1 overflow-hidden rounded-full bg-elevated">
        <div className="bg-accent" style={{ width: `${home}%` }} />
        <div className="bg-info" style={{ width: `${100 - home}%` }} />
      </div>
      <span className="tnum w-7 text-right text-[10px] text-info">{100 - home}%</span>
    </div>
  );
}

function BracketMatch({ f, probs, wide = false }: { f: Fixture; probs?: MatchProbs | undefined; wide?: boolean }) {
  const { t, kickoffDay, kickoffTime } = useFormat();
  const decided = f.status === 'finished' && f.homeScore !== null && f.awayScore !== null;
  const showProbs = !!probs && !!f.home.team && !!f.away.team && f.status !== 'finished';
  return (
    <Link
      to="/match/$num"
      params={{ num: String(f.num) }}
      className={cn(
        'block overflow-hidden rounded-lg border border-line bg-panel text-sm transition-colors hover:border-line-strong',
        wide ? 'w-full' : 'w-52',
      )}
    >
      <Side slot={f.home} score={f.homeScore} winner={decided && f.homeScore! > f.awayScore!} />
      <div className="h-px bg-line" />
      <Side slot={f.away} score={f.awayScore} winner={decided && f.awayScore! > f.homeScore!} />
      {showProbs && <AdvanceBar probs={probs} />}
      <div className="border-t border-line bg-surface-2 px-2.5 py-1 text-[11px] text-faint">
        {fmt(t.common.matchNumberShort, { num: f.num })} · {f.status === 'finished' ? t.common.fullTimeShort : `${kickoffDay(f.kickoff)} ${kickoffTime(f.kickoff)}`}
      </div>
    </Link>
  );
}

export function BracketPage() {
  const t = useT();
  const snapshot = useTournamentStore((s) => s.snapshot);
  const model = useTournamentStore((s) => s.model);
  const probsByNum = useMemo(
    () => new Map((model?.matches ?? []).map((m) => [m.num, m.probs])),
    [model],
  );

  const { byStage, third } = useMemo(() => {
    const fixtures = snapshot?.fixtures ?? [];
    const byStage: Record<Stage, Fixture[]> = {
      group: [], r32: [], r16: [], qf: [], sf: [], third: [], final: [],
    };
    for (const f of fixtures) if (f.stage !== 'group') byStage[f.stage].push(f);
    for (const s of Object.keys(byStage) as Stage[]) byStage[s].sort((a, b) => a.num - b.num);
    return { byStage, third: byStage.third[0] };
  }, [snapshot]);

  const [mobileStage, setMobileStage] = useState<KnockoutStage>('r32');
  const [whatIf, setWhatIf] = useState(false);
  const [picks, setPicks] = useState<Picks>({});
  const [ratings, setRatings] = useState<RatingsModel | null>(null);

  const fixtures = useMemo(() => snapshot?.fixtures ?? [], [snapshot]);

  useEffect(() => {
    if (!whatIf || ratings) return;
    fetch('/data/ratings.json').then((r) => r.json()).then((d: RatingsModel) => setRatings(d)).catch(() => {});
  }, [whatIf, ratings]);

  const eff = useMemo(() => (whatIf ? effectiveBracket(fixtures, picks) : null), [whatIf, fixtures, picks]);

  /** model probability the home side advances, for a (possibly hypothetical) pairing */
  const advHomeFor = (f: Fixture, m: EffMatch): number | null => {
    if (!ratings || !m.home || !m.away) return null;
    const adv = hostAdvantage(m.home, m.away, f.venue, ratings.params.homeAdvElo);
    const p = predictMatch(m.home, m.away, ratings, adv);
    return knockoutAdvanceProb(p.probs, p.eloHome, p.eloAway);
  };

  const champ = useMemo(() => {
    if (!whatIf || !eff) return null;
    const path = championPath(fixtures, eff);
    if (!path || !ratings) return path ? { ...path, chance: null as number | null } : null;
    let chance = 1;
    for (const num of path.matchNums) {
      const f = fixtures.find((x) => x.num === num);
      const m = eff.get(num);
      if (!f || !m) continue;
      const advHome = advHomeFor(f, m);
      if (advHome == null) { chance = -1; break; }
      chance *= m.winner === m.home ? advHome : 1 - advHome;
    }
    return { ...path, chance: chance < 0 ? null : chance };
  }, [whatIf, eff, fixtures, ratings]);

  const onPick = (num: number) => (side: PickSide) => {
    setPicks((prev) => {
      const next: Picks = { ...prev };
      if (next[num] === side) delete next[num];
      else next[num] = side;
      return prunePicks(fixtures, next);
    });
  };

  const renderMatch = (f: Fixture, wide = false): ReactNode => {
    if (whatIf && eff) {
      const m = eff.get(f.num);
      if (m) {
        return (
          <WhatIfMatch
            key={f.num} f={f} eff={m} pick={picks[f.num]}
            advHome={m.decided ? null : advHomeFor(f, m)}
            onPick={onPick(f.num)} wide={wide}
          />
        );
      }
    }
    return <BracketMatch key={f.num} f={f} probs={probsByNum.get(f.num)} wide={wide} />;
  };

  return (
    <div>
      <PageHeader
        title={t.bracket.title}
        subtitle={whatIf ? t.bracket.whatIfHint : t.bracket.subtitle}
        actions={
          <div className="flex items-center gap-2">
            {whatIf && Object.keys(picks).length > 0 && (
              <button
                type="button"
                onClick={() => setPicks({})}
                className="rounded-md border border-line px-3 py-1.5 text-sm font-medium text-muted hover:bg-elevated hover:text-ink"
              >
                {t.bracket.reset}
              </button>
            )}
            <button
              type="button"
              onClick={() => setWhatIf((v) => !v)}
              className={cn(
                'inline-flex items-center gap-1.5 rounded-md border px-3 py-1.5 text-sm font-medium',
                whatIf ? 'border-accent/40 bg-accent-glow text-accent' : 'border-line text-muted hover:bg-elevated hover:text-ink',
              )}
            >
              <Wand2 size={15} /> {t.bracket.whatIf}
            </button>
          </div>
        }
      />

      {whatIf && champ?.champion && (
        <div className="mb-4 flex flex-wrap items-center gap-3 rounded-xl border border-gold/40 bg-gold/10 px-4 py-3">
          <span aria-hidden className="text-2xl">{teamFlag(champ.champion)}</span>
          <span className="font-display font-bold text-ink">{fmt(t.bracket.champion, { team: champ.champion })}</span>
          {champ.chance != null && (
            <span className="tnum text-sm text-muted">
              {fmt(t.bracket.pathChance, { pct: champ.chance >= 0.0005 ? `${(champ.chance * 100).toFixed(1)}%` : '<0.1%' })}
            </span>
          )}
        </div>
      )}

      {/* Mobile: one round at a time behind a segmented picker — no sideways scroll. */}
      <div className="md:hidden">
        <div className="mb-4 flex overflow-hidden rounded-lg border border-line text-xs font-bold">
          {COLUMN_STAGES.map((stage) => (
            <button
              key={stage}
              type="button"
              onClick={() => setMobileStage(stage)}
              className={cn(
                'flex-1 py-2.5 uppercase tracking-wide transition-colors',
                stage === mobileStage ? 'bg-accent-glow text-accent' : 'text-muted hover:text-ink',
              )}
            >
              {t.team.stageShort[stage]}
            </button>
          ))}
        </div>
        <h2 className="smallcaps mb-2">{t.stage[mobileStage]}</h2>
        <div className="flex flex-col gap-3">
          {byStage[mobileStage].length
            ? byStage[mobileStage].map((f) => renderMatch(f, true))
            : <div className="h-20 animate-pulse rounded-lg border border-line bg-panel" />}
          {mobileStage === 'final' && third && (
            <>
              <h2 className="smallcaps mt-3">{t.bracket.thirdPlacePlayoff}</h2>
              {renderMatch(third, true)}
            </>
          )}
        </div>
      </div>

      {/* Desktop: all rounds side by side. */}
      <div className="hidden md:block">
        <div className="overflow-x-auto pb-4">
          <div className="flex gap-5">
            {COLUMN_STAGES.map((stage) => (
              <div key={stage} className="flex shrink-0 flex-col gap-3">
                <h2 className="smallcaps">{t.stage[stage]}</h2>
                {byStage[stage].length
                  ? byStage[stage].map((f) => renderMatch(f))
                  : <div className="h-20 w-52 animate-pulse rounded-lg border border-line bg-panel" />}
              </div>
            ))}
          </div>
        </div>

        {third && (
          <div className="mt-2">
            <h2 className="smallcaps mb-2">{t.bracket.thirdPlacePlayoff}</h2>
            {renderMatch(third)}
          </div>
        )}
      </div>
    </div>
  );
}
