import { useEffect, useState } from "react";
import { Link } from "@tanstack/react-router";
import { BookOpen, ClipboardList, Flag, Trophy, Users } from "lucide-react";
import { toast } from "sonner";
import { DeskHero, DeskSkeleton, StatTile } from "@/components/desk-hero";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { AssignmentEditorList } from "@/components/academy-assignments";
import { OpenDealRoom } from "@/components/stadium/deal-room";
import { StaffEditField } from "@/components/staff-edit";
import { firstName } from "@/lib/identity";
import {
  coachAwardCredit,
  coachRemoveStudent,
  coachReplaceStudent,
  coachSuggestAssignment,
  getInstructorDesk,
  gradeSubmission,
  rsvpStudentGameDay,
} from "@/lib/server/api-academy";
import { creditLine, INSTRUCTOR_POWERS, STAFF_ONLY_POWERS } from "@/lib/coach-powers";
import { formatDateTime } from "@/lib/utils";

type Desk = Awaited<ReturnType<typeof getInstructorDesk>>;
type Member = Desk["roster"][number];
export type InstructorSection = "all" | "roster" | "courses" | "review";

function PowersCard() {
  return (
    <Card className="mb-6">
      <CardContent className="pt-5">
        <h2 className="font-display text-xl">Instructor vs Super Admin</h2>
        <p className="mt-1 text-sm text-navy">
          You own the students. Super Admin owns the institution. Credit is a two-step: you recommend, they approve.
        </p>
        <div className="mt-4 grid gap-4 sm:grid-cols-2">
          <div>
            <p className="text-[11px] font-semibold tracking-[0.16em] text-gold-ink uppercase">Coach can</p>
            <ul className="mt-2 list-disc space-y-1 pl-5 text-sm text-navy">
              {INSTRUCTOR_POWERS.map((p) => (
                <li key={p}>{p}</li>
              ))}
            </ul>
          </div>
          <div>
            <p className="text-[11px] font-semibold tracking-[0.16em] text-gold-ink uppercase">Super Admin only</p>
            <ul className="mt-2 list-disc space-y-1 pl-5 text-sm text-navy">
              {STAFF_ONLY_POWERS.map((p) => (
                <li key={p}>{p}</li>
              ))}
            </ul>
          </div>
        </div>
      </CardContent>
    </Card>
  );
}

export function InstructorHome({
  email,
  section = "all",
}: {
  email: string;
  section?: InstructorSection;
}) {
  const [data, setData] = useState<Desk | null>(null);

  async function load() {
    const next = await getInstructorDesk({ data: { email } });
    setData(next);
  }

  useEffect(() => {
    let live = true;
    void getInstructorDesk({ data: { email } }).then((d) => {
      if (live) setData(d);
    });
    return () => {
      live = false;
    };
  }, [email]);

  if (!data) return <DeskSkeleton />;
  if (!data.user) {
    return <p className="text-sm text-navy">No coach record is attached to this account.</p>;
  }

  const { user, courses, roster, reviewQueue, teams, events, assignments, modules, wins, progress, analytics } = data;
  const showAll = section === "all";

  return (
    <div className="stagger-in">
      {showAll ? (
        <DeskHero
          kicker={`Instructor · ${user.title ?? "Coach"}`}
          title={`Coach desk, ${firstName(user.full_name)}`}
          description="You own the students: roster, gradebook, special assignments, Game Day RSVP. You recommend internship or college credit. Super Admin approves it — and still owns grants and the org profile."
        />
      ) : null}

      {showAll ? <PowersCard /> : null}

      {showAll ? (
        <div className="mb-6 grid gap-3 sm:grid-cols-2 lg:grid-cols-4">
          <StatTile icon={Users} label="On your clipboard" value={roster.filter((m) => m.eligibility === "active").length} hint="Active athletes you coach" />
          <StatTile icon={BookOpen} label="Class progress" value={`${analytics.avgProgress}%`} hint="Average across enrollments. Not a GPA." />
          <StatTile icon={Flag} label="At risk" value={analytics.atRisk} hint="Under 30% through their classes" />
          <StatTile icon={ClipboardList} label="Waiting on a grade" value={analytics.waiting} hint={`${analytics.credits} credit records posted`} />
        </div>
      ) : null}

      {section === "all" || section === "roster" ? (
        <div className={section === "all" ? "mb-6 grid gap-6 lg:grid-cols-5" : "mb-6"}>
          <div className={section === "all" ? "space-y-6 lg:col-span-3" : "space-y-6"}>
            <RosterCard email={email} roster={roster} onChanged={load} />
            {showAll ? <ProgressCard progress={progress} /> : null}
            {showAll ? <UpcomingCurriculum courses={courses} modules={modules} /> : null}
            {showAll ? <WinsPanel wins={wins} /> : null}
          </div>
          {showAll ? (
            <div className="space-y-6 lg:col-span-2">
              <TeamsYouCoach teams={teams} roster={roster} />
              <SpecialAssignmentForm email={email} courses={courses} onSaved={load} />
              <ReviewPanel items={reviewQueue} />
              <EventsPanel email={email} events={events} onChanged={load} />
            </div>
          ) : null}
        </div>
      ) : null}

      {section === "courses" ? <CoursesPanel courses={courses} assignments={assignments} onReload={load} /> : null}
      {section === "review" ? (
        <GradebookPanel email={email} items={reviewQueue} onSaved={load} />
      ) : null}
    </div>
  );
}

function RosterCard({
  email,
  roster,
  onChanged,
}: {
  email: string;
  roster: Member[];
  onChanged: () => Promise<void>;
}) {
  const [open, setOpen] = useState<string | null>(null);
  const [busy, setBusy] = useState(false);
  const [replaceId, setReplaceId] = useState("");
  const [credit, setCredit] = useState<"internship" | "college_credit" | "passed" | "none">("internship");
  const [note, setNote] = useState("");

  async function remove(m: Member) {
    setBusy(true);
    try {
      await coachRemoveStudent({ data: { email, memberId: m.id } });
      toast.success(`${m.full_name} is off the venture. They stay in class unless you drop the enrollment later.`);
      setOpen(null);
      await onChanged();
    } catch (err) {
      toast.error(err instanceof Error ? err.message : "Could not remove.");
    } finally {
      setBusy(false);
    }
  }

  async function replace(m: Member) {
    if (!replaceId) {
      toast.error("Pick who takes the slot.");
      return;
    }
    setBusy(true);
    try {
      const result = await coachReplaceStudent({ data: { email, memberId: m.id, replacementId: replaceId } });
      toast.success(`${result.out} is benched. ${result.inn} takes the slot.`);
      setOpen(null);
      setReplaceId("");
      await onChanged();
    } catch (err) {
      toast.error(err instanceof Error ? err.message : "Could not replace.");
    } finally {
      setBusy(false);
    }
  }

  async function award(m: Member) {
    setBusy(true);
    try {
      await coachAwardCredit({ data: { email, memberId: m.id, status: credit, note } });
      toast.success(`Recommended for ${m.full_name}. Super Admin has to approve before the registrar sees it.`);
      setOpen(null);
      setNote("");
      await onChanged();
    } catch (err) {
      toast.error(err instanceof Error ? err.message : "Could not record credit.");
    } finally {
      setBusy(false);
    }
  }

  return (
    <Card>
      <CardContent className="pt-5">
        <div className="mb-2 flex items-center justify-between gap-2">
          <div>
            <div className="flex items-center gap-2">
              <Users className="size-4 text-primary" />
              <h2 className="font-display text-xl">Your roster — cut, replace, credit</h2>
            </div>
            <p className="mt-1 text-sm text-navy">
              A coach can remove an athlete from the venture, put someone else in the slot, or recommend internship /
              college credit. Super Admin approves the credit. Grants stay with staff.
            </p>
          </div>
          <Link to="/coach/roster" className="shrink-0 text-sm font-semibold text-primary hover:underline">
            Full roster
          </Link>
        </div>
        <ul className="divide-y divide-border">
          {roster.map((m) => (
            <li key={m.id} className="py-3">
              <div className="flex flex-wrap items-start justify-between gap-2">
                <div>
                  <p className="text-sm font-semibold text-navy">{m.full_name}</p>
                  <p className="text-xs text-navy">
                    {m.member_no} · {m.sport ?? m.track} · {m.team_name ?? "No team"} · {m.avg_progress ?? 0}% through
                    classes
                  </p>
                  <p className="mt-1 text-xs font-medium text-navy">
                    {creditLine(m.credit_status, m.credit_stage)}
                    {m.eligibility !== "active" ? ` · ${m.eligibility}` : ""}
                    {m.traction ? " · traction" : ""}
                  </p>
                </div>
                <div className="flex flex-wrap gap-2">
                  {m.eligibility === "active" && m.team_id ? (
                    <>
                      <Button size="sm" variant="outline" onClick={() => setOpen(open === `rm-${m.id}` ? null : `rm-${m.id}`)}>
                        Remove
                      </Button>
                      <Button size="sm" variant="outline" onClick={() => setOpen(open === `rp-${m.id}` ? null : `rp-${m.id}`)}>
                        Replace
                      </Button>
                    </>
                  ) : null}
                  <Button size="sm" variant="gold" onClick={() => setOpen(open === `cr-${m.id}` ? null : `cr-${m.id}`)}>
                    Recommend credit
                  </Button>
                </div>
              </div>
              {open === `rm-${m.id}` ? (
                <div className="mt-3 rounded-lg bg-muted/70 px-3 py-3">
                  <p className="text-sm text-navy">
                    Cut {m.full_name} from {m.team_name}? They stay enrolled in class. The venture slot opens.
                  </p>
                  <Button className="mt-2" size="sm" disabled={busy} onClick={() => void remove(m)}>
                    Confirm remove
                  </Button>
                </div>
              ) : null}
              {open === `rp-${m.id}` ? (
                <div className="mt-3 rounded-lg bg-muted/70 px-3 py-3">
                  <p className="text-sm text-navy">Who takes {m.full_name}’s slot on {m.team_name}?</p>
                  <select
                    className="mt-2 h-9 w-full rounded-md border border-input bg-background px-2 text-sm"
                    value={replaceId}
                    onChange={(e) => setReplaceId(e.target.value)}
                  >
                    <option value="">Select athlete</option>
                    {roster
                      .filter((x) => x.id !== m.id)
                      .map((x) => (
                        <option key={x.id} value={x.id}>
                          {x.full_name} · {x.team_name ?? x.eligibility}
                        </option>
                      ))}
                  </select>
                  <Button className="mt-2" size="sm" variant="gold" disabled={busy} onClick={() => void replace(m)}>
                    Confirm replace
                  </Button>
                </div>
              ) : null}
              {open === `cr-${m.id}` ? (
                <div className="mt-3 rounded-lg bg-muted/70 px-3 py-3">
                  <p className="text-sm font-semibold text-navy">Recommend academic credit</p>
                  <p className="mt-1 text-xs text-navy">
                    Step 1 of 2. You attest they earned internship or college credit. Super Admin approves. Their
                    registrar still posts the credit. CFL is not the university.
                  </p>
                  <select
                    className="mt-2 h-9 w-full rounded-md border border-input bg-background px-2 text-sm"
                    value={credit}
                    onChange={(e) => setCredit(e.target.value as typeof credit)}
                  >
                    <option value="internship">Internship — academic credit</option>
                    <option value="college_credit">College credit</option>
                    <option value="passed">Pass the class</option>
                    <option value="none">Not for credit</option>
                  </select>
                  <Label className="mt-2 block" htmlFor={`note-${m.id}`}>
                    Note to the sending school
                  </Label>
                  <Input
                    id={`note-${m.id}`}
                    className="mt-1"
                    value={note}
                    onChange={(e) => setNote(e.target.value)}
                    placeholder="Completed CFL-201 Customer Discovery as internship hours."
                  />
                  <Button className="mt-2" size="sm" variant="gold" disabled={busy} onClick={() => void award(m)}>
                    Recommend to Super Admin
                  </Button>
                </div>
              ) : null}
            </li>
          ))}
        </ul>
      </CardContent>
    </Card>
  );
}

function ProgressCard({ progress }: { progress: Desk["progress"] }) {
  const byStudent = new Map<string, Desk["progress"]>();
  for (const row of progress) {
    const list = byStudent.get(row.member_id) ?? [];
    list.push(row);
    byStudent.set(row.member_id, list);
  }
  return (
    <Card>
      <CardContent className="pt-5">
        <h2 className="font-display text-xl">Student progress</h2>
        <p className="mt-1 mb-3 text-sm text-navy">
          Percent finished in each class. Under 30% is at-risk. This is progress, not a test score.
        </p>
        {progress.length === 0 ? (
          <p className="text-sm text-navy">No enrollments on your teams yet.</p>
        ) : (
          <ul className="space-y-4">
            {[...byStudent.entries()].map(([id, rows]) => (
              <li key={id}>
                <p className="text-sm font-semibold text-navy">{rows[0]?.full_name}</p>
                <ul className="mt-1 space-y-1">
                  {rows.map((r) => (
                    <li key={`${id}-${r.course_code}`} className="flex items-center justify-between gap-3 text-sm text-navy">
                      <span>
                        {r.course_code} · {r.course_title}
                      </span>
                      <span className="tabular font-semibold">{r.progress_pct}%</span>
                    </li>
                  ))}
                </ul>
              </li>
            ))}
          </ul>
        )}
      </CardContent>
    </Card>
  );
}

function SpecialAssignmentForm({
  email,
  courses,
  onSaved,
}: {
  email: string;
  courses: Desk["courses"];
  onSaved: () => Promise<void>;
}) {
  const [courseId, setCourseId] = useState(courses[0]?.id ?? "");
  const [title, setTitle] = useState("");
  const [prompt, setPrompt] = useState("");
  const [due, setDue] = useState("");
  const [busy, setBusy] = useState(false);

  async function save() {
    setBusy(true);
    try {
      await coachSuggestAssignment({
        data: { email, courseId, title, prompt, due_at: due || undefined },
      });
      toast.success("Special assignment is on the student desk.");
      setTitle("");
      setPrompt("");
      await onSaved();
    } catch (err) {
      toast.error(err instanceof Error ? err.message : "Could not post the assignment.");
    } finally {
      setBusy(false);
    }
  }

  return (
    <Card>
      <CardContent className="pt-5">
        <h2 className="font-display text-xl">Special class assignment</h2>
        <p className="mt-1 mb-3 text-sm text-navy">
          Extra work for this week — a film session write-up, a clinic interview, a brand-kit rewrite. Students see it
          on their desk the next time they load.
        </p>
        {courses.length === 0 ? (
          <p className="text-sm text-navy">No class is on your name, so there is nowhere to hang the assignment.</p>
        ) : (
          <div className="space-y-2">
            <Label htmlFor="sp-course">Class</Label>
            <select
              id="sp-course"
              className="h-9 w-full rounded-md border border-input bg-background px-2 text-sm"
              value={courseId}
              onChange={(e) => setCourseId(e.target.value)}
            >
              {courses.map((c) => (
                <option key={c.id} value={c.id}>
                  {c.code} · {c.title}
                </option>
              ))}
            </select>
            <Label htmlFor="sp-title">Title</Label>
            <Input id="sp-title" value={title} onChange={(e) => setTitle(e.target.value)} placeholder="Saturday film notes" />
            <Label htmlFor="sp-prompt">Prompt</Label>
            <textarea
              id="sp-prompt"
              className="min-h-20 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"
              value={prompt}
              onChange={(e) => setPrompt(e.target.value)}
              placeholder="Watch Friday’s Game Day tape. Write the one claim the team is allowed to make."
            />
            <Label htmlFor="sp-due">Due</Label>
            <Input id="sp-due" type="date" value={due} onChange={(e) => setDue(e.target.value)} />
            <Button variant="gold" disabled={busy || !courseId} onClick={() => void save()}>
              {busy ? "Posting…" : "Assign to the class"}
            </Button>
          </div>
        )}
      </CardContent>
    </Card>
  );
}

function UpcomingCurriculum({
  courses,
  modules,
}: {
  courses: Desk["courses"];
  modules: Desk["modules"];
}) {
  return (
    <Card>
      <CardContent className="pt-5">
        <div className="mb-3 flex items-center justify-between gap-2">
          <div>
            <div className="flex items-center gap-2">
              <BookOpen className="size-4 text-primary" />
              <h2 className="font-display text-xl">What you are teaching</h2>
            </div>
            <p className="mt-1 text-sm text-navy">Classes on your name, plus the next modules.</p>
          </div>
          <Link to="/coach/courses" className="text-sm font-semibold text-primary hover:underline">
            Edit assignments
          </Link>
        </div>
        <ul className="space-y-3">
          {courses.map((c) => (
            <li key={c.id} className="rounded-lg bg-muted/60 px-3 py-3">
              <div className="flex items-baseline justify-between gap-2">
                <p className="text-sm font-semibold text-navy">
                  {c.code} · {c.title}
                </p>
                <span className="text-xs font-medium text-navy">
                  {c.quarter} · {c.enrolled} enrolled
                </span>
              </div>
              <p className="mt-1 text-sm text-navy">{c.summary}</p>
            </li>
          ))}
          {courses.length === 0 ? <li className="text-sm text-navy">No class is on your name yet.</li> : null}
        </ul>
        {modules.length > 0 ? (
          <div className="mt-4 border-t border-border pt-4">
            <p className="mb-2 text-[11px] font-semibold tracking-[0.16em] text-gold-ink uppercase">Coming up in class</p>
            <ol className="space-y-2">
              {modules.map((m) => (
                <li key={m.id}>
                  <p className="text-xs font-medium text-navy">
                    {m.course_code} · week {m.week}
                  </p>
                  <p className="text-sm font-semibold text-navy">{m.title}</p>
                  <p className="text-sm text-navy">{m.summary}</p>
                </li>
              ))}
            </ol>
          </div>
        ) : null}
      </CardContent>
    </Card>
  );
}

function WinsPanel({ wins }: { wins: Desk["wins"] }) {
  return (
    <Card>
      <CardContent className="pt-5">
        <h2 className="font-display text-xl">Student accomplishments</h2>
        <p className="mt-1 mb-3 text-sm text-navy">Graded work on your classes. A score is a grade, not stadium yards.</p>
        {wins.length === 0 ? (
          <p className="text-sm text-navy">Nothing graded yet this week.</p>
        ) : (
          <ul className="space-y-3">
            {wins.map((w, i) => (
              <li key={`${w.full_name}-${w.title}-${i}`} className="rounded-lg bg-muted/50 px-3 py-3">
                <p className="text-sm font-semibold text-navy">{w.full_name}</p>
                <p className="text-sm text-navy">
                  {w.title} · {w.course_title}
                  {w.team_name ? ` · ${w.team_name}` : ""}
                </p>
                <p className="mt-1 text-xs font-semibold text-navy">Grade {w.score ?? "—"}</p>
              </li>
            ))}
          </ul>
        )}
      </CardContent>
    </Card>
  );
}

function TeamsYouCoach({
  teams,
  roster,
}: {
  teams: Desk["teams"];
  roster: Desk["roster"];
}) {
  return (
    <Card>
      <CardContent className="pt-5">
        <h2 className="mb-1 font-display text-xl">Teams you coach</h2>
        <p className="mb-3 text-sm text-navy">Studio ventures on your clipboard. CFL takes no equity.</p>
        <ul className="space-y-4">
          {teams.map((t) => {
            const people = roster.filter((m) => m.team_name === t.name && m.eligibility === "active");
            return (
              <li key={t.id} className="rounded-lg bg-muted/50 px-3 py-3">
                <p className="text-sm font-semibold text-navy">{t.name}</p>
                <p className="mt-1 text-sm text-navy">{t.venture_summary}</p>
                <div className="mt-2">
                  <StaffEditField
                    table="teams"
                    id={t.id}
                    field="venture_summary"
                    value={t.venture_summary}
                    label="team summary"
                  />
                </div>
                <p className="mt-1 text-xs font-medium text-navy">
                  {people.length} athletes · {t.yard_points} academy yards
                </p>
                {people.length > 0 ? (
                  <p className="mt-1 text-xs text-navy">{people.map((p) => p.full_name).join(" · ")}</p>
                ) : null}
                {t.capstone_slug ? <OpenDealRoom slug={t.capstone_slug} label={`Open ${t.name} deal room`} /> : null}
              </li>
            );
          })}
        </ul>
      </CardContent>
    </Card>
  );
}

function CoursesPanel({
  courses,
  assignments,
  onReload,
}: {
  courses: Desk["courses"];
  assignments: Desk["assignments"];
  onReload: () => Promise<void>;
}) {
  return (
    <div className="space-y-6">
      <Card>
        <CardContent className="pt-5">
          <div className="mb-3 flex items-center gap-2">
            <BookOpen className="size-4 text-primary" />
            <h2 className="font-display text-xl">Courses you teach</h2>
          </div>
          <p className="mb-3 text-sm text-navy">
            Students see your name as the instructor. Edit the assignments below. Super Admin can edit them too.
          </p>
          <ul className="space-y-3">
            {courses.map((c) => (
              <li key={c.id} className="rounded-lg bg-muted/60 px-3 py-3">
                <div className="flex items-baseline justify-between gap-2">
                  <p className="text-sm font-semibold text-navy">
                    {c.code} · {c.title}
                  </p>
                  <Badge variant="muted">{c.quarter}</Badge>
                </div>
                <p className="mt-1 text-sm text-navy">{c.summary}</p>
                <div className="mt-2">
                  <StaffEditField
                    table="courses"
                    id={c.id}
                    field="summary"
                    value={c.summary}
                    label="course summary"
                    onSaved={onReload}
                  />
                </div>
                <p className="mt-1 text-xs font-medium text-navy">
                  {c.enrolled} enrolled · Instructor of record: {c.instructor_name ?? "You"}
                </p>
              </li>
            ))}
          </ul>
        </CardContent>
      </Card>
      <Card>
        <CardContent className="pt-5">
          <h2 className="mb-1 font-display text-xl">Assignments you can edit</h2>
          <p className="mb-3 text-sm text-navy">
            Trainer interviews, spending film, brand kit, tax set-aside, prototype photos. Change the prompt here.
          </p>
          <AssignmentEditorList items={assignments} onSaved={() => void onReload()} />
        </CardContent>
      </Card>
    </div>
  );
}

function ReviewPanel({ items }: { items: Desk["reviewQueue"] }) {
  const waiting = items.filter((s) => s.status === "submitted");
  return (
    <Card>
      <CardContent className="pt-5">
        <div className="mb-3 flex items-center justify-between gap-2">
          <div className="flex items-center gap-2">
            <ClipboardList className="size-4 text-primary" />
            <h2 className="font-display text-xl">Gradebook</h2>
          </div>
          <Link to="/coach/review" className="text-sm font-semibold text-primary hover:underline">
            Open gradebook
          </Link>
        </div>
        <p className="mb-3 text-sm text-navy">
          {waiting.length} waiting on a score. Students see the number and your note on their desk.
        </p>
        {waiting.length === 0 ? (
          <p className="text-sm text-navy">Inbox is clear.</p>
        ) : (
          <ul className="space-y-3">
            {waiting.slice(0, 4).map((s) => (
              <li key={s.id}>
                <p className="text-sm font-semibold text-navy">{s.title}</p>
                <p className="text-xs text-navy">
                  {s.full_name} · {s.course_title}
                </p>
              </li>
            ))}
          </ul>
        )}
      </CardContent>
    </Card>
  );
}

function GradebookPanel({
  email,
  items,
  onSaved,
}: {
  email: string;
  items: Desk["reviewQueue"];
  onSaved: () => Promise<void>;
}) {
  const [open, setOpen] = useState<string | null>(null);
  const [score, setScore] = useState("90");
  const [note, setNote] = useState("");
  const [busy, setBusy] = useState(false);

  async function save(id: string) {
    setBusy(true);
    try {
      await gradeSubmission({ data: { email, submissionId: id, score: Number(score), feedback: note } });
      toast.success("Posted to the student gradebook.");
      setOpen(null);
      setNote("");
      await onSaved();
    } catch (err) {
      toast.error(err instanceof Error ? err.message : "Could not post the grade.");
    } finally {
      setBusy(false);
    }
  }

  return (
    <Card>
      <CardContent className="pt-5">
        <h2 className="font-display text-xl">Gradebook</h2>
        <p className="mt-1 mb-4 text-sm text-navy">
          Score is 0–100. The student sees the number and this note. Super Admin can override a grade you already
          posted. Stadium yards are a different scoreboard.
        </p>
        {items.length === 0 ? (
          <p className="text-sm text-navy">No papers in the book yet.</p>
        ) : (
          <ul className="space-y-3">
            {items.map((s) => (
              <li key={s.id} className="rounded-lg bg-muted/50 px-3 py-3">
                <div className="flex flex-wrap items-start justify-between gap-2">
                  <div>
                    <p className="text-sm font-semibold text-navy">{s.title}</p>
                    <p className="text-xs text-navy">
                      {s.full_name} · {s.course_title} · {s.points} pts
                    </p>
                    {s.status === "graded" ? (
                      <p className="mt-1 text-sm font-semibold text-navy">
                        Graded {s.score}
                        {s.feedback ? ` · ${s.feedback}` : ""}
                      </p>
                    ) : (
                      <p className="mt-1 text-xs font-medium text-navy">Submitted — waiting on you</p>
                    )}
                  </div>
                  <Button
                    size="sm"
                    variant={s.status === "graded" ? "outline" : "gold"}
                    onClick={() => {
                      setOpen(open === s.id ? null : s.id);
                      setScore(String(s.score ?? 90));
                      setNote(s.feedback ?? "");
                    }}
                  >
                    {s.status === "graded" ? "Override" : "Grade"}
                  </Button>
                </div>
                {open === s.id ? (
                  <div className="mt-3 grid gap-2 sm:grid-cols-[6rem_1fr] sm:items-end">
                    <div>
                      <Label htmlFor={`sc-${s.id}`}>Score</Label>
                      <Input
                        id={`sc-${s.id}`}
                        className="mt-1"
                        inputMode="numeric"
                        value={score}
                        onChange={(e) => setScore(e.target.value.replace(/[^\d]/g, ""))}
                      />
                    </div>
                    <div>
                      <Label htmlFor={`fb-${s.id}`}>Note to the student</Label>
                      <Input id={`fb-${s.id}`} className="mt-1" value={note} onChange={(e) => setNote(e.target.value)} />
                    </div>
                    <Button className="sm:col-span-2" size="sm" variant="gold" disabled={busy} onClick={() => void save(s.id)}>
                      Post to gradebook
                    </Button>
                  </div>
                ) : null}
              </li>
            ))}
          </ul>
        )}
      </CardContent>
    </Card>
  );
}

function EventsPanel({
  email,
  events,
  onChanged,
}: {
  email: string;
  events: Desk["events"];
  onChanged: () => Promise<void>;
}) {
  const [busy, setBusy] = useState<string | null>(null);

  async function rsvp(id: string, status: "registered" | "out") {
    setBusy(id);
    try {
      await rsvpStudentGameDay({ data: { email, gameDayId: id, status } });
      toast.success(status === "registered" ? "You’re in. We’ll collect you at the door." : "We’ll mark you out.");
      await onChanged();
    } catch (err) {
      toast.error(err instanceof Error ? err.message : "Could not save RSVP.");
    } finally {
      setBusy(null);
    }
  }

  return (
    <Card>
      <CardContent className="pt-5">
        <h2 className="mb-1 font-display text-xl">Upcoming Game Days</h2>
        <p className="mb-3 text-sm text-navy">Register if you will attend. We collect coaches at the door the same as students.</p>
        <ul className="space-y-3">
          {events.map((e) => (
            <li key={e.id} className="rounded-lg bg-muted/50 px-3 py-3">
              <p className="text-sm font-semibold text-navy">{e.title}</p>
              <p className="text-xs text-navy">
                {formatDateTime(e.starts_at)} · {e.location}
              </p>
              <p className="mt-1 text-xs font-semibold text-navy">
                {e.rsvp_status === "registered" ? "You’re attending" : e.rsvp_status === "out" ? "You’re out" : "No RSVP yet"}
              </p>
              <div className="mt-2 flex flex-wrap gap-2">
                <Button size="sm" variant="gold" disabled={busy === e.id} onClick={() => void rsvp(e.id, "registered")}>
                  I’ll attend
                </Button>
                <Button size="sm" variant="outline" disabled={busy === e.id} onClick={() => void rsvp(e.id, "out")}>
                  Can’t make it
                </Button>
              </div>
            </li>
          ))}
        </ul>
      </CardContent>
    </Card>
  );
}
