import { lazy, Suspense, useState, type ComponentType } from "react";
import { Link, useNavigate } from "@tanstack/react-router";
import { Armchair, Bell, Flag, Mail, RefreshCw, Trophy, Vote } from "lucide-react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
  castStadiumVote,
  getStadiumBoard,
  subscribeStadiumAlert,
  type MemberScore,
  type StadiumPlay,
  type StadiumTeamBoard,
} from "@/lib/server/api-stadium";
import {
  ARENA_META,
  ARENAS,
  EVENT_CATALOG,
  arenaProgress,
  downLabel,
  footballFromPoints,
  type ArenaId,
} from "@/lib/stadium-scoring";
import { pingStadiumLive, useStadiumLive } from "@/lib/stadium-live";
import { useRoleStore } from "@/lib/role-store";
import { formatDateTime } from "@/lib/utils";
import { cn } from "@/lib/utils";
import { LiveBadge } from "./live-strip";

const SeatExplore = (
  import.meta.env.SSR
    ? () => null
    : lazy(() => import("./seat-3d").then((m) => ({ default: m.SeatExplore })))
) as ComponentType<{
  scores: {
    home: StadiumTeamBoard;
    away: StadiumTeamBoard | null;
    watching: number;
    link: ReturnType<typeof useStadiumLive>["link"];
    arena: ArenaId;
    plays: import("@/lib/server/api-stadium").StadiumPlay[];
    email: string;
    onMoved: () => Promise<void>;
  };
  onExit: () => void;
}>;
const SpeedwayDrive = (
  import.meta.env.SSR
    ? () => null
    : lazy(() => import("./speedway-3d").then((m) => ({ default: m.SpeedwayDrive })))
) as ComponentType<{
  home: StadiumTeamBoard;
  away: StadiumTeamBoard;
  watching: number;
  link: ReturnType<typeof useStadiumLive>["link"];
  onExit: () => void;
}>;

type Board = Awaited<ReturnType<typeof getStadiumBoard>>;

export function ArenaBoard({
  arena,
  initial,
  view,
}: {
  arena: ArenaId;
  initial: Board;
  view?: "seat" | "drive";
}) {
  const { board, setBoard, link, watching } = useStadiumLive(arena, initial);
  const email = useRoleStore((s) => s.email);
  const account = useRoleStore((s) => s.account());
  const [busy, setBusy] = useState(false);
  const navigate = useNavigate();
  const meta = ARENA_META[arena];
  const home = board.home;
  const away = board.away;

  async function reload() {
    const next = await getStadiumBoard({ data: { arena } });
    setBoard(next);
  }

  function leaveView() {
    void navigate({ to: "/public/stadium/$arena", params: { arena }, search: {} });
  }

  if (!home) {
    return (
      <div className="stadium-root px-4 py-16 text-center">
        <p className="font-display text-2xl">No live matchup yet.</p>
        <Button asChild className="mt-4">
          <Link to="/public/stadium">Back to the hall</Link>
        </Button>
      </div>
    );
  }

  if (view === "seat") {
    return (
      <Suspense fallback={<div className="stadium-game"><p className="stadium-game-fallback">Opening the bowl…</p></div>}>
        <SeatExplore
          scores={{
            home,
            away,
            watching,
            link,
            arena,
            plays: board.plays,
            email: account.email && account.email !== "public@capitalforgeleague.org" ? account.email : email,
            onMoved: async () => {
              pingStadiumLive();
              await reload();
            },
          }}
          onExit={leaveView}
        />
      </Suspense>
    );
  }

  if (view === "drive") {
    return (
      <Suspense fallback={<div className="stadium-game"><p className="stadium-game-fallback">Warming the oval…</p></div>}>
        <SpeedwayDrive home={home} away={away ?? home} watching={watching} link={link} onExit={leaveView} />
      </Suspense>
    );
  }

  const rival = away && away.id !== home.id ? away : null;
  const homeFb = footballFromPoints(home.points);
  const awayFb = rival ? footballFromPoints(rival.points) : null;
  const homeProg = arenaProgress(arena, home.points);
  const awayProg = rival ? arenaProgress(arena, rival.points) : null;

  return (
    <div className="stadium-root pb-12">
      <div className="stadium-arena min-h-[22rem] sm:min-h-[26rem]">
        <img src={meta.image} alt="" />
        <div className="stadium-arena-copy">
          <div className="mb-4 flex flex-wrap items-center justify-between gap-3">
            <div>
              <p className="text-[11px] font-medium tracking-[0.2em] text-primary uppercase">
                {board.match?.round_label ?? "Sweet 16"} · {meta.name}
              </p>
              <p className="mt-1 text-xs text-sidebar-muted">Public scoreboard · same points in every arena</p>
            </div>
            <div className="flex flex-wrap gap-2">
              <LiveBadge link={link} watching={watching} />
              <Button asChild variant="outline" size="sm" className="border-sidebar-border bg-navy/50 text-sidebar-foreground">
                <Link to="/public/stadium">Change stadium</Link>
              </Button>
              <Button size="sm" variant="outline" className="border-sidebar-border bg-navy/50 text-sidebar-foreground" onClick={() => void reload()}>
                <RefreshCw className="size-3.5" />
                Refresh
              </Button>
            </div>
          </div>

          <div className="scorebug">
            <div className="scorebug-team text-left">
              <p>{rival ? "Home" : "Showcase"}</p>
              <p className="truncate font-display text-lg text-sidebar-foreground sm:text-xl">{home.name}</p>
              <p className="mt-1 text-xs text-sidebar-muted">
                {home.points} pts · {home.votes} votes
              </p>
            </div>
            <div className="scorebug-mid">
              <p className="scorebug-num tabular">
                {homeFb.displayScore}
                {awayFb ? (
                  <>
                    <span className="mx-1 text-primary">–</span>
                    {awayFb.displayScore}
                  </>
                ) : null}
              </p>
              <p className="mt-1 text-[10px] font-medium tracking-[0.18em] text-live uppercase">Live</p>
            </div>
            <div className="scorebug-team text-right">
              {rival ? (
                <>
                  <p>Away</p>
                  <p className="truncate font-display text-lg text-sidebar-foreground sm:text-xl">{rival.name}</p>
                  <p className="mt-1 text-xs text-sidebar-muted">
                    {rival.points} pts · {rival.votes} votes
                  </p>
                </>
              ) : (
                <>
                  <p>Wrap</p>
                  <p className="truncate font-display text-lg text-sidebar-foreground sm:text-xl">One venture night</p>
                  <p className="mt-1 text-xs text-sidebar-muted">{home.category}</p>
                </>
              )}
            </div>
          </div>

          <div className="mt-4 grid gap-2 sm:grid-cols-2">
            <DriveReadout label={rival ? "Home drive" : "Drive"} team={home} progress={homeProg.label} fb={homeFb} />
            {rival && awayProg ? <DriveReadout label="Away drive" team={rival} progress={awayProg.label} fb={awayFb!} /> : null}
          </div>

          {rival && arena === "football" ? (
            <FootballField home={home} away={rival} />
          ) : rival ? (
            <GenericTrack arena={arena} home={home} away={rival} />
          ) : (
            <GenericTrack arena={arena} home={home} away={home} />
          )}

          <div className="mt-4 flex flex-wrap gap-2">
            <Button asChild>
              <Link to="/public/stadium/$arena" params={{ arena }} search={{ view: "seat" }}>
                <Armchair className="size-4" />
                Take your seat
              </Link>
            </Button>
            <Button asChild variant="outline" className="border-sidebar-border bg-navy/50 text-sidebar-foreground">
              <Link to="/public/stadium/$arena" params={{ arena: "speedway" }} search={{ view: "drive" }}>
                <Flag className="size-4" />
                Racing tools
              </Link>
            </Button>
          </div>
        </div>
      </div>

      <div className="mx-auto grid max-w-6xl gap-4 px-4 py-6 lg:grid-cols-5 sm:px-6">
        <div className="space-y-4 lg:col-span-3">
          <PlayLog plays={board.plays} homeId={home.id} />
          <HowItWorks />
        </div>
        <div className="space-y-4 lg:col-span-2">
          <FanActions
            home={home}
            away={rival ?? home}
            defaultEmail={account.email && account.email !== "public@capitalforgeleague.org" ? account.email : email}
            busy={busy}
            setBusy={setBusy}
            onDone={async () => {
              pingStadiumLive();
              await reload();
            }}
          />
          <RosterCard roster={board.roster ?? []} homeId={home.id} />
          <ArenaSwitcher current={arena} />
        </div>
      </div>
    </div>
  );
}

function DriveReadout({
  label,
  team,
  progress,
  fb,
}: {
  label: string;
  team: StadiumTeamBoard;
  progress: string;
  fb: ReturnType<typeof footballFromPoints>;
}) {
  return (
    <div className="rounded-lg border border-sidebar-border bg-navy/70 px-3 py-2 backdrop-blur-sm">
      <p className="text-[10px] font-medium tracking-[0.16em] text-sidebar-muted uppercase">{label}</p>
      <p className="font-display text-sidebar-foreground">{team.name}</p>
      <p className="tabular text-sm text-primary">
        {downLabel(fb)} · ball on {fb.ballOn} · {progress}
      </p>
    </div>
  );
}

function FootballField({ home, away }: { home: StadiumTeamBoard; away: StadiumTeamBoard }) {
  const marks = [10, 20, 30, 40, 50, 40, 30, 20, 10, ""];
  return (
    <div className="cfl-field-wrap mt-3">
      <div className="cfl-field" role="img" aria-label={`${home.name} at ${home.driveYards} yards, ${away.name} at ${away.driveYards} yards`}>
        {marks.map((n, i) => (
          <span key={i} className="cfl-field-yard" style={{ left: `${i * 10}%` }}>
            {n}
          </span>
        ))}
        <span className="cfl-field-mid">CFL</span>
        <span className="cfl-fd" style={{ left: `${Math.min(99, home.driveYards + home.toGo)}%` }} />
        <span className="cfl-ball cfl-ball-home" style={{ left: `${Math.min(98, Math.max(2, home.driveYards))}%` }} title={`${home.name} ${home.driveYards} yd`} />
        <span className="cfl-ball cfl-ball-away" style={{ left: `${Math.min(98, Math.max(2, away.driveYards))}%` }} title={`${away.name} ${away.driveYards} yd`} />
      </div>
      <p className="mt-2 text-center text-[11px] text-sidebar-muted">
        Gold ball is the drive. Yellow stem is the first-down marker. Four yards to go.
      </p>
    </div>
  );
}

function GenericTrack({ arena, home, away }: { arena: ArenaId; home: StadiumTeamBoard; away: StadiumTeamBoard }) {
  const hp = arenaProgress(arena, home.points);
  const ap = arenaProgress(arena, away.points);
  return (
    <div className="mt-4 space-y-3 rounded-lg border border-sidebar-border bg-navy/70 p-4 backdrop-blur-sm">
      <TrackRow name={home.name} value={hp.value} max={hp.max} label={hp.label} />
      <TrackRow name={away.name} value={ap.value} max={ap.max} label={ap.label} />
    </div>
  );
}

function TrackRow({ name, value, max, label }: { name: string; value: number; max: number; label: string }) {
  const pct = Math.max(4, Math.min(100, (value / max) * 100));
  return (
    <div>
      <div className="mb-1 flex items-baseline justify-between gap-3">
        <p className="text-sm font-medium text-sidebar-foreground">{name}</p>
        <p className="tabular text-xs text-primary">{label}</p>
      </div>
      <div className="progress-bar bg-sidebar-border">
        <span style={{ width: `${pct}%` }} />
      </div>
    </div>
  );
}

function PlayLog({ plays, homeId }: { plays: StadiumPlay[]; homeId: string }) {
  return (
    <div className="rounded-xl border border-sidebar-border bg-sidebar-accent/80 p-5">
      <div className="mb-3 flex items-center gap-2">
        <Trophy className="size-4 text-primary" />
        <h2 className="font-display text-xl text-sidebar-foreground">Play by play</h2>
      </div>
      <p className="mb-3 text-xs text-sidebar-muted">Recorded and public. Deal-room filings move the ball the same as a vote.</p>
      <ul className="play-log">
        {plays.map((p) => {
          const spec = EVENT_CATALOG[p.event_type as keyof typeof EVENT_CATALOG];
          return (
            <li key={p.id} className="flex items-start justify-between gap-3 py-2.5">
              <div className="min-w-0">
                <p className="text-sm text-sidebar-foreground">
                  <span className={p.team_id === homeId ? "text-primary" : "text-sidebar-muted"}>{p.team_name}</span>
                  {" · "}
                  {spec?.label ?? p.event_type.replaceAll("_", " ")}
                </p>
                <p className="truncate text-xs text-sidebar-muted">
                  {p.note}
                  {p.member_name ? ` · ${p.member_name}` : null}
                </p>
                <p className="mt-0.5 text-[11px] text-sidebar-muted">{formatDateTime(p.created_at)}</p>
              </div>
              <span className="tabular text-sm font-semibold text-primary">+{p.points}</span>
            </li>
          );
        })}
        {plays.length === 0 ? <li className="py-4 text-sm text-sidebar-muted">No plays yet tonight.</li> : null}
      </ul>
    </div>
  );
}

function HowItWorks() {
  return (
    <div className="rounded-xl border border-sidebar-border bg-sidebar-accent/80 p-5">
      <h2 className="font-display text-xl text-sidebar-foreground">Scoring, recorded</h2>
      <ul className="mt-3 space-y-1.5 text-sm text-sidebar-muted">
        <li>1 business point = 1 yard.</li>
        <li>4 yards = a first down.</li>
        <li>100 yards = an 8-point score — not 6+1.</li>
        <li>Every arena uses this engine. Only the camera changes.</li>
      </ul>
    </div>
  );
}

function FanActions({
  home,
  away,
  defaultEmail,
  busy,
  setBusy,
  onDone,
}: {
  home: StadiumTeamBoard;
  away: StadiumTeamBoard;
  defaultEmail: string;
  busy: boolean;
  setBusy: (v: boolean) => void;
  onDone: () => Promise<void>;
}) {
  const [email, setEmail] = useState(defaultEmail === "public@capitalforgeleague.org" ? "" : defaultEmail);
  const [teamId, setTeamId] = useState(home.id);

  async function vote() {
    setBusy(true);
    try {
      const res = await castStadiumVote({ data: { email, teamId } });
      toast.success(`Vote recorded · ${res.points} yards. The ball moved.`);
      await onDone();
    } catch (err) {
      toast.error(err instanceof Error ? err.message : "Could not record the vote.");
    } finally {
      setBusy(false);
    }
  }

  async function alertMe() {
    setBusy(true);
    try {
      await subscribeStadiumAlert({ data: { email, teamId } });
      toast.success("You’re on the alert list. We’ll email when this team moves the ball.");
    } catch (err) {
      toast.error(err instanceof Error ? err.message : "Could not save the alert.");
    } finally {
      setBusy(false);
    }
  }

  return (
    <div className="rounded-xl border border-sidebar-border bg-sidebar-accent/80 p-5">
      <div className="mb-3 flex items-center gap-2">
        <Vote className="size-4 text-primary" />
        <h2 className="font-display text-xl text-sidebar-foreground">Fans & alerts</h2>
      </div>
      <p className="text-sm text-sidebar-muted">
        A public vote is 3 yards. Leave an email if you want a note when the studio files a packet.
      </p>
      <label className="mt-4 block text-[11px] font-medium tracking-[0.16em] text-sidebar-muted uppercase">
        Email
        <Input
          className="mt-1 border-sidebar-border bg-navy text-sidebar-foreground"
          type="email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          placeholder="you@email.com"
        />
      </label>
      <label className="mt-3 block text-[11px] font-medium tracking-[0.16em] text-sidebar-muted uppercase">
        Team
        <select
          className="mt-1 flex h-10 w-full rounded-md border border-sidebar-border bg-navy px-3 text-sm text-sidebar-foreground"
          value={teamId}
          onChange={(e) => setTeamId(e.target.value)}
        >
          <option value={home.id}>{home.name}</option>
          <option value={away.id}>{away.name}</option>
        </select>
      </label>
      <div className="mt-4 grid gap-2">
        <Button disabled={busy || !email.includes("@")} onClick={() => void vote()}>
          <Mail className="size-4" />
          Cast a 3-yard vote
        </Button>
        <Button
          variant="outline"
          className="border-sidebar-border bg-transparent text-sidebar-foreground"
          disabled={busy || !email.includes("@")}
          onClick={() => void alertMe()}
        >
          <Bell className="size-4" />
          Email me when they score
        </Button>
      </div>
    </div>
  );
}

function RosterCard({ roster, homeId }: { roster: MemberScore[]; homeId: string }) {
  return (
    <div className="rounded-xl border border-sidebar-border bg-sidebar-accent/80 p-5">
      <h2 className="font-display text-xl text-sidebar-foreground">Tonight’s athletes</h2>
      <p className="mt-1 text-xs text-sidebar-muted">Stadium points are public. Traction flags the ones a coach may move.</p>
      <ul className="mt-3 space-y-2">
        {roster.map((m) => (
          <li key={m.member_id} className="flex items-center gap-2.5">
            <span className="flex size-8 items-center justify-center rounded-full bg-navy text-xs font-semibold text-sidebar-foreground">
              {m.initials}
            </span>
            <div className="min-w-0 flex-1">
              <p className="truncate text-sm text-sidebar-foreground">{m.full_name}</p>
              <p className="truncate text-[11px] text-sidebar-muted">
                {m.team_name}
                {m.team_id === homeId ? " · home" : " · away"}
              </p>
            </div>
            <div className="text-right">
              <p className="tabular text-sm font-semibold text-primary">{m.stadium_points}</p>
              {m.traction ? (
                <p className="text-[10px] font-medium tracking-wide text-live uppercase">Traction</p>
              ) : null}
            </div>
          </li>
        ))}
      </ul>
    </div>
  );
}

function ArenaSwitcher({ current }: { current: ArenaId }) {
  return (
    <div className="rounded-xl border border-sidebar-border bg-sidebar-accent/80 p-5">
      <p className="text-[11px] font-medium tracking-[0.16em] text-sidebar-muted uppercase">Same points · other cameras</p>
      <div className="mt-3 grid grid-cols-2 gap-2">
        {ARENAS.map((id) => (
          <Link
            key={id}
            to="/public/stadium/$arena"
            params={{ arena: id }}
            className={cn(
              "rounded-lg px-3 py-2 text-center text-sm",
              id === current ? "bg-primary/20 text-primary" : "bg-navy/40 text-sidebar-muted hover:text-sidebar-foreground",
            )}
          >
            {ARENA_META[id].hallLabel}
          </Link>
        ))}
      </div>
    </div>
  );
}

