"use client";

import { useCallback, useEffect, useMemo, useRef, useState, useTransition } from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import clsx from "clsx";
import {
  ChevronDown,
  ChevronLeft,
  ChevronRight,
  Filter,
  Link2,
  Loader2,
  Save,
  Sparkles,
} from "lucide-react";
import { bulkUpdateAssessmentAction, updateAssessmentAction, type AssessmentSaveData } from "@/app/actions/assessment";
import type { ActionResult } from "@/app/actions/shared";
import { buttonClass, Callout, Card, CardHeader, inputClass, ProgressBar, selectClass, StatCard, TableShell, Td, Th } from "@/components/ui";
import { useToast } from "@/components/toast";
import { ASSESSMENT_STATUS_LABELS, AssessmentStatusBadge, formatPercent, formatUnits } from "@/components/status";
import { ASSESSMENT_STATUSES, type AssessmentStatus, type YearLongCreditPolicy } from "@/types";
import { EquivalencyDialog } from "@/components/students/equivalency-dialog";

/**
 * The student curriculum assessment workspace (SPEC 16, 31).
 *
 * Designed for encoding 212 students quickly: keyboard navigation, collapsible
 * terms, filters, bulk status updates, and an explicit saved/unsaved indicator.
 * Every save round-trips to the server, which recomputes credited units,
 * completion percentage and year level — the browser never computes them.
 */

export interface AssessmentRowView {
  courseId: string;
  courseCode: string;
  courseTitle: string;
  units: number;
  lectureUnits: number | null;
  laboratoryUnits: number | null;
  prerequisiteText: string | null;
  countsTowardProgramUnits: boolean;
  isYearLong: boolean;
  isFinalComponent: boolean;
  partnerCodes: string[];
  status: AssessmentStatus;
  gradeRaw: string;
  remarks: string;
  equivalentSourceSchool: string;
  equivalentCourseCode: string;
  equivalentCourseTitle: string;
  equivalentSourceUnits: number | null;
  approvedCreditedUnitsOverride: number | null;
  countedUnits: number;
  credited: boolean;
  awaitingFinalGrade: boolean;
  updatedAt: string | null;
}

export interface AssessmentGroupView {
  intended_year: number;
  term: string;
  units: number;
  creditedUnits: number;
  rows: AssessmentRowView[];
}

type RowFilter = "ALL" | "INCOMPLETE" | "CREDITED" | "VALIDATION";

const YEAR_LABELS: Record<number, string> = {
  1: "First Year",
  2: "Second Year",
  3: "Third Year",
  4: "Fourth Year",
  5: "Fifth Year",
};

export function AssessmentWorkspace({
  studentId,
  groups,
  initialSummary,
  canEdit,
  canApproveEquivalency,
  displayPrecision,
  yearLongPolicy,
  navigation,
}: {
  studentId: string;
  groups: AssessmentGroupView[];
  initialSummary: AssessmentSaveData;
  canEdit: boolean;
  canApproveEquivalency: boolean;
  displayPrecision: number;
  yearLongPolicy: YearLongCreditPolicy;
  navigation: { previous: { id: string; label: string } | null; next: { id: string; label: string } | null };
}) {
  const router = useRouter();
  const { toast } = useToast();
  const [, startTransition] = useTransition();

  const [rows, setRows] = useState(() => new Map(groups.flatMap((g) => g.rows).map((r) => [r.courseId, r])));
  // Saves are fired from event handlers and timeouts, so they must read the
  // latest row state rather than the value captured when the handler was made.
  const rowsRef = useRef(rows);
  const [dirty, setDirty] = useState<Set<string>>(new Set());
  const [saving, setSaving] = useState<Set<string>>(new Set());
  const [summary, setSummary] = useState(initialSummary);
  const [filter, setFilter] = useState<RowFilter>("ALL");
  const [collapsed, setCollapsed] = useState<Set<string>>(new Set());
  const [selected, setSelected] = useState<Set<string>>(new Set());
  const [bulkStatus, setBulkStatus] = useState<AssessmentStatus>("PASSED");
  const [bulkPending, setBulkPending] = useState(false);
  const [equivalencyFor, setEquivalencyFor] = useState<string | null>(null);
  const tableRef = useRef<HTMLDivElement>(null);

  // Re-sync when the server sends new props (e.g. after router.refresh()).
  useEffect(() => {
    setRows(new Map(groups.flatMap((g) => g.rows).map((r) => [r.courseId, r])));
    setDirty(new Set());
  }, [groups]);

  useEffect(() => setSummary(initialSummary), [initialSummary]);

  useEffect(() => {
    rowsRef.current = rows;
  }, [rows]);

  const markDirty = useCallback((courseId: string) => {
    setDirty((current) => new Set(current).add(courseId));
  }, []);

  const patchRow = useCallback(
    (courseId: string, patch: Partial<AssessmentRowView>) => {
      setRows((current) => {
        const next = new Map(current);
        const row = next.get(courseId);
        if (row) next.set(courseId, { ...row, ...patch });
        return next;
      });
      markDirty(courseId);
    },
    [markDirty],
  );

  const applySummary = useCallback((data: AssessmentSaveData) => {
    setSummary(data);
    const credited = new Set(data.creditedCourseIds);
    setRows((current) => {
      const next = new Map<string, AssessmentRowView>();
      for (const [id, row] of current) {
        const isCredited = credited.has(id);
        const override = row.approvedCreditedUnitsOverride;
        next.set(id, {
          ...row,
          credited: isCredited,
          countedUnits: isCredited ? (override === null ? row.units : Math.min(Math.max(override, 0), row.units)) : 0,
          awaitingFinalGrade:
            row.isYearLong &&
            yearLongPolicy === "ON_FINAL_PASS" &&
            !isCredited &&
            (row.status === "PASSED" || row.status === "CREDITED"),
        });
      }
      return next;
    });
  }, [yearLongPolicy]);

  const saveRow = useCallback(
    async (courseId: string, overrides?: Partial<AssessmentRowView>) => {
      const base = rowsRef.current.get(courseId);
      if (!base || !canEdit) return;
      const row = overrides ? { ...base, ...overrides } : base;

      setSaving((current) => new Set(current).add(courseId));
      const formData = new FormData();
      formData.set("student_id", studentId);
      formData.set("curriculum_course_id", courseId);
      formData.set("status", row.status);
      formData.set("grade_raw", row.gradeRaw ?? "");
      formData.set("remarks", row.remarks ?? "");
      formData.set("equivalent_source_school", row.equivalentSourceSchool ?? "");
      formData.set("equivalent_course_code", row.equivalentCourseCode ?? "");
      formData.set("equivalent_course_title", row.equivalentCourseTitle ?? "");
      formData.set("equivalent_source_units", row.equivalentSourceUnits === null ? "" : String(row.equivalentSourceUnits));
      formData.set(
        "approved_credited_units_override",
        row.approvedCreditedUnitsOverride === null ? "" : String(row.approvedCreditedUnitsOverride),
      );

      const result: ActionResult<AssessmentSaveData> = await updateAssessmentAction(
        { ok: false, message: null },
        formData,
      );

      setSaving((current) => {
        const next = new Set(current);
        next.delete(courseId);
        return next;
      });

      if (result.ok && result.data) {
        setDirty((current) => {
          const next = new Set(current);
          next.delete(courseId);
          return next;
        });
        applySummary(result.data);
        if (result.data.calculationError) {
          toast({ tone: "error", title: "Completion could not be calculated", description: result.data.calculationError });
        }
        return true;
      }
      toast({
        tone: "error",
        title: result.message ?? "The change could not be saved.",
        description: Object.values(result.fieldErrors ?? {})[0],
      });
      return false;
    },
    [canEdit, studentId, applySummary, toast],
  );

  const saveAllDirty = useCallback(async () => {
    const ids = [...dirty];
    if (ids.length === 0) {
      toast({ tone: "info", title: "Nothing to save", description: "All changes are already saved." });
      return;
    }
    for (const id of ids) await saveRow(id);
    toast({ tone: "success", title: `Saved ${ids.length} course${ids.length === 1 ? "" : "s"}.` });
    startTransition(() => router.refresh());
  }, [dirty, saveRow, toast, router]);

  // Ctrl/Cmd + S saves everything that is unsaved.
  useEffect(() => {
    if (!canEdit) return;
    const handler = (event: KeyboardEvent) => {
      if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "s") {
        event.preventDefault();
        void saveAllDirty();
      }
    };
    window.addEventListener("keydown", handler);
    return () => window.removeEventListener("keydown", handler);
  }, [canEdit, saveAllDirty]);

  // Warn before leaving with unsaved edits.
  useEffect(() => {
    if (dirty.size === 0) return;
    const handler = (event: BeforeUnloadEvent) => event.preventDefault();
    window.addEventListener("beforeunload", handler);
    return () => window.removeEventListener("beforeunload", handler);
  }, [dirty.size]);

  const runBulk = useCallback(async () => {
    if (selected.size === 0) return;
    setBulkPending(true);
    const formData = new FormData();
    formData.set("student_id", studentId);
    formData.set("status", bulkStatus);
    for (const id of selected) formData.append("curriculum_course_ids", id);

    const result = await bulkUpdateAssessmentAction({ ok: false, message: null }, formData);
    setBulkPending(false);

    if (result.ok && result.data) {
      setRows((current) => {
        const next = new Map(current);
        for (const id of selected) {
          const row = next.get(id);
          if (row) next.set(id, { ...row, status: bulkStatus });
        }
        return next;
      });
      applySummary(result.data);
      setSelected(new Set());
      setDirty(new Set());
      toast({ tone: "success", title: result.message ?? "Bulk update applied." });
      startTransition(() => router.refresh());
    } else {
      toast({ tone: "error", title: result.message ?? "The bulk update failed." });
    }
  }, [selected, studentId, bulkStatus, applySummary, toast, router]);

  const visibleGroups = useMemo(() => {
    return groups
      .map((group) => ({
        ...group,
        rows: group.rows
          .map((r) => rows.get(r.courseId) ?? r)
          .filter((row) => {
            if (filter === "ALL") return true;
            if (filter === "CREDITED") return row.credited;
            if (filter === "VALIDATION") return row.status === "FOR_VALIDATION";
            return !row.credited;
          }),
      }))
      .filter((group) => group.rows.length > 0);
  }, [groups, rows, filter]);

  const allRows = useMemo(() => [...rows.values()], [rows]);
  const equivalencyRow = equivalencyFor ? (rows.get(equivalencyFor) ?? null) : null;

  const toggleGroup = (key: string) =>
    setCollapsed((current) => {
      const next = new Set(current);
      if (next.has(key)) next.delete(key);
      else next.add(key);
      return next;
    });

  /** Arrow-key movement between grade inputs, for fast encoding. */
  const onGradeKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
    if (event.key !== "ArrowDown" && event.key !== "ArrowUp" && event.key !== "Enter") return;
    const inputs = Array.from(tableRef.current?.querySelectorAll<HTMLInputElement>("input[data-grade]") ?? []);
    const index = inputs.indexOf(event.currentTarget);
    if (index === -1) return;
    const nextIndex = event.key === "ArrowUp" ? index - 1 : index + 1;
    if (nextIndex >= 0 && nextIndex < inputs.length) {
      event.preventDefault();
      inputs[nextIndex].focus();
      inputs[nextIndex].select();
    }
  };

  return (
    <div className="space-y-4">
      {/* Live computed summary */}
      <div className="grid grid-cols-2 gap-3 lg:grid-cols-4">
        <StatCard
          label="Credited units"
          value={formatUnits(summary.creditedUnits)}
          hint={`of ${formatUnits(summary.totalProgramUnits)} total program units`}
        />
        <StatCard
          label="Completion percentage"
          value={summary.calculationError ? "Error" : formatPercent(summary.displayPercentage, displayPrecision)}
          hint={
            summary.calculationError ? (
              summary.calculationError
            ) : (
              <ProgressBar value={summary.displayPercentage} label="Completion percentage" />
            )
          }
          tone={summary.calculationError ? "rose" : "brand"}
        />
        <StatCard
          label="OCCP year level"
          value={summary.yearLevel ?? "—"}
          hint="Computed by the server from the unrounded percentage"
          tone="teal"
        />
        <StatCard
          label="Courses credited"
          value={`${summary.creditedCourseCount} / ${summary.totalCourseCount}`}
          hint={`${formatUnits(summary.remainingUnits)} units remaining`}
        />
      </div>

      {/* Toolbar */}
      <Card>
        <div className="flex flex-wrap items-center gap-2 border-b border-ink-200 px-4 py-3">
          <div className="flex items-center gap-1.5 text-[12px] font-medium text-ink-500">
            <Filter className="h-3.5 w-3.5" aria-hidden />
            Show
          </div>
          <div className="flex flex-wrap gap-1" role="group" aria-label="Filter courses">
            {(
              [
                ["ALL", "All courses"],
                ["INCOMPLETE", "Incomplete only"],
                ["CREDITED", "Credited only"],
                ["VALIDATION", "For validation"],
              ] as const
            ).map(([value, label]) => (
              <button
                key={value}
                type="button"
                onClick={() => setFilter(value)}
                aria-pressed={filter === value}
                className={clsx(
                  "rounded-md px-2.5 py-1 text-[12px] font-medium transition-colors",
                  filter === value ? "bg-brand-600 text-white" : "text-ink-600 hover:bg-ink-100",
                )}
              >
                {label}
              </button>
            ))}
          </div>

          <div className="ml-auto flex flex-wrap items-center gap-2">
            {navigation.previous ? (
              <Link
                href={`/students/${navigation.previous.id}/assessment`}
                className={buttonClass("ghost", "sm")}
                title={navigation.previous.label}
              >
                <ChevronLeft className="h-3.5 w-3.5" aria-hidden />
                Previous
              </Link>
            ) : null}
            {navigation.next ? (
              <Link
                href={`/students/${navigation.next.id}/assessment`}
                className={buttonClass("ghost", "sm")}
                title={navigation.next.label}
              >
                Next
                <ChevronRight className="h-3.5 w-3.5" aria-hidden />
              </Link>
            ) : null}

            {canEdit ? (
              <>
                <span
                  className={clsx(
                    "rounded-full px-2.5 py-1 text-[11px] font-semibold",
                    dirty.size > 0 ? "bg-amber-50 text-amber-700" : "bg-teal-50 text-teal-700",
                  )}
                  role="status"
                >
                  {dirty.size > 0 ? `${dirty.size} unsaved change${dirty.size === 1 ? "" : "s"}` : "All changes saved"}
                </span>
                <button
                  type="button"
                  onClick={() => void saveAllDirty()}
                  className={buttonClass("primary", "sm")}
                  disabled={dirty.size === 0}
                  title="Ctrl/Cmd + S"
                >
                  <Save className="h-3.5 w-3.5" aria-hidden />
                  Save changes
                </button>
              </>
            ) : (
              <span className="rounded-full bg-ink-100 px-2.5 py-1 text-[11px] font-medium text-ink-600">
                Read-only
              </span>
            )}
          </div>
        </div>

        {/* Bulk actions */}
        {canEdit && selected.size > 0 ? (
          <div className="flex flex-wrap items-center gap-2 border-b border-brand-200 bg-brand-50 px-4 py-2.5">
            <span className="text-[13px] font-medium text-brand-800">
              {selected.size} course{selected.size === 1 ? "" : "s"} selected
            </span>
            <select
              value={bulkStatus}
              onChange={(event) => setBulkStatus(event.target.value as AssessmentStatus)}
              aria-label="Bulk status"
              className={`${selectClass} h-8 w-auto py-0`}
            >
              {ASSESSMENT_STATUSES.map((status) => (
                <option key={status} value={status}>
                  {ASSESSMENT_STATUS_LABELS[status]}
                </option>
              ))}
            </select>
            <button type="button" onClick={() => void runBulk()} className={buttonClass("primary", "sm")} disabled={bulkPending}>
              {bulkPending ? <Loader2 className="h-3.5 w-3.5 animate-spin" aria-hidden /> : <Sparkles className="h-3.5 w-3.5" aria-hidden />}
              Apply to selected
            </button>
            <button type="button" onClick={() => setSelected(new Set())} className={buttonClass("ghost", "sm")}>
              Clear selection
            </button>
          </div>
        ) : null}

        {/* Course table, grouped by year and term */}
        <div ref={tableRef}>
          {visibleGroups.length === 0 ? (
            <p className="px-5 py-10 text-center text-[13px] text-ink-500">
              No courses match this filter.
            </p>
          ) : (
            visibleGroups.map((group) => {
              const key = `${group.intended_year}::${group.term}`;
              const isCollapsed = collapsed.has(key);
              const groupRowIds = group.rows.map((r) => r.courseId);
              const allSelected = groupRowIds.every((id) => selected.has(id));

              return (
                <section key={key} aria-label={`${YEAR_LABELS[group.intended_year] ?? `Year ${group.intended_year}`} ${group.term}`}>
                  <div className="flex flex-wrap items-center gap-3 border-b border-ink-200 bg-ink-50 px-4 py-2">
                    <button
                      type="button"
                      onClick={() => toggleGroup(key)}
                      aria-expanded={!isCollapsed}
                      className="flex items-center gap-1.5 text-[13px] font-semibold text-ink-800 hover:text-brand-700"
                    >
                      <ChevronDown className={clsx("h-4 w-4 transition-transform", isCollapsed && "-rotate-90")} aria-hidden />
                      {YEAR_LABELS[group.intended_year] ?? `Year ${group.intended_year}`} — {group.term}
                    </button>
                    <span className="tabular text-[12px] text-ink-500">
                      {group.rows.length} course{group.rows.length === 1 ? "" : "s"} ·{" "}
                      <span className="font-medium text-ink-700">
                        {formatUnits(group.creditedUnits)} / {formatUnits(group.units)}
                      </span>{" "}
                      units credited
                    </span>
                    {canEdit ? (
                      <label className="ml-auto flex items-center gap-1.5 text-[12px] text-ink-600">
                        <input
                          type="checkbox"
                          checked={allSelected && groupRowIds.length > 0}
                          onChange={(event) =>
                            setSelected((current) => {
                              const next = new Set(current);
                              for (const id of groupRowIds) {
                                if (event.target.checked) next.add(id);
                                else next.delete(id);
                              }
                              return next;
                            })
                          }
                          className="h-3.5 w-3.5 rounded border-ink-300 text-brand-600 focus:ring-brand-500"
                        />
                        Select term
                      </label>
                    ) : null}
                  </div>

                  {!isCollapsed ? (
                    <TableShell>
                      <thead className="sr-only">
                        <tr>
                          {canEdit ? <Th>Select</Th> : null}
                          <Th>Course code</Th>
                          <Th>Course title</Th>
                          <Th align="right">Units</Th>
                          <Th>Grade</Th>
                          <Th>Status</Th>
                          <Th align="right">Counted units</Th>
                          <Th>Equivalency and remarks</Th>
                        </tr>
                      </thead>
                      <tbody>
                        {group.rows.map((row) => {
                          const isDirty = dirty.has(row.courseId);
                          const isSaving = saving.has(row.courseId);
                          return (
                            <tr
                              key={row.courseId}
                              className={clsx(
                                "hover:bg-ink-50",
                                isDirty && "bg-amber-50/60",
                                row.credited && !isDirty && "bg-teal-50/40",
                              )}
                            >
                              {canEdit ? (
                                <Td className="w-8">
                                  <input
                                    type="checkbox"
                                    checked={selected.has(row.courseId)}
                                    onChange={(event) =>
                                      setSelected((current) => {
                                        const next = new Set(current);
                                        if (event.target.checked) next.add(row.courseId);
                                        else next.delete(row.courseId);
                                        return next;
                                      })
                                    }
                                    aria-label={`Select ${row.courseCode}`}
                                    className="h-3.5 w-3.5 rounded border-ink-300 text-brand-600 focus:ring-brand-500"
                                  />
                                </Td>
                              ) : null}

                              <Td className="w-36 align-top">
                                <span className="block font-medium text-ink-900">{row.courseCode}</span>
                                {row.isYearLong ? (
                                  <span
                                    className="mt-0.5 inline-flex items-center gap-1 text-[10px] font-medium text-brand-700"
                                    title={`Year-long subject, paired with ${row.partnerCodes.join(", ")}. The final grade is recorded at the end of the second semester.`}
                                  >
                                    <Link2 className="h-3 w-3" aria-hidden />
                                    Year-long{row.isFinalComponent ? " (final)" : ""}
                                  </span>
                                ) : null}
                              </Td>

                              <Td className="min-w-[16rem] align-top">
                                <span className="block text-[13px] leading-snug text-ink-800">{row.courseTitle}</span>
                                {row.prerequisiteText ? (
                                  <span className="mt-0.5 block text-[11px] leading-snug text-ink-400">
                                    Prereq: {row.prerequisiteText}
                                  </span>
                                ) : null}
                                {!row.countsTowardProgramUnits ? (
                                  <span className="mt-0.5 block text-[11px] font-medium text-amber-700">
                                    Does not count toward program units
                                  </span>
                                ) : null}
                              </Td>

                              <Td align="right" className="tabular w-16 align-top whitespace-nowrap">
                                {formatUnits(row.units)}
                                {row.lectureUnits !== null && row.laboratoryUnits !== null ? (
                                  <span className="block text-[10px] text-ink-400">
                                    {formatUnits(row.lectureUnits)}L / {formatUnits(row.laboratoryUnits)}Lab
                                  </span>
                                ) : null}
                              </Td>

                              <Td className="w-24 align-top">
                                <input
                                  data-grade
                                  value={row.gradeRaw ?? ""}
                                  onChange={(event) => patchRow(row.courseId, { gradeRaw: event.target.value })}
                                  onBlur={() => {
                                    if (!isDirty) return;
                                    void saveRow(row.courseId).then((saved) => {
                                      if (saved) startTransition(() => router.refresh());
                                    });
                                  }}
                                  onKeyDown={onGradeKeyDown}
                                  disabled={!canEdit}
                                  aria-label={`Grade for ${row.courseCode}`}
                                  placeholder="—"
                                  maxLength={20}
                                  className={`${inputClass} tabular h-8 py-0 text-[13px]`}
                                />
                              </Td>

                              <Td className="w-40 align-top">
                                <select
                                  value={row.status}
                                  onChange={(event) => {
                                    const status = event.target.value as AssessmentStatus;
                                    patchRow(row.courseId, { status });
                                    // Status is the authoritative crediting signal, so persist at
                                    // once, passing the new value explicitly.
                                    void saveRow(row.courseId, { status }).then((saved) => {
                                      if (saved) startTransition(() => router.refresh());
                                    });
                                  }}
                                  disabled={!canEdit}
                                  aria-label={`Status for ${row.courseCode}`}
                                  className={`${selectClass} h-8 py-0 text-[13px]`}
                                >
                                  {ASSESSMENT_STATUSES.map((status) => (
                                    <option key={status} value={status}>
                                      {ASSESSMENT_STATUS_LABELS[status]}
                                    </option>
                                  ))}
                                </select>
                                {row.awaitingFinalGrade ? (
                                  <span className="mt-1 block text-[10px] leading-snug text-amber-700">
                                    Credit is held until the final second-semester grade for {row.partnerCodes.join(", ")}
                                    {" "}is recorded.
                                  </span>
                                ) : null}
                              </Td>

                              <Td align="right" className="tabular w-20 align-top">
                                <span
                                  className={clsx(
                                    "font-semibold",
                                    row.countedUnits > 0 ? "text-teal-700" : "text-ink-400",
                                  )}
                                >
                                  {formatUnits(row.countedUnits)}
                                </span>
                                {isSaving ? (
                                  <Loader2 className="ml-1 inline h-3 w-3 animate-spin text-ink-400" aria-label="Saving" />
                                ) : null}
                              </Td>

                              <Td className="min-w-[14rem] align-top">
                                {row.equivalentCourseCode || row.equivalentSourceSchool ? (
                                  <span className="block text-[11px] leading-snug text-ink-600">
                                    <span className="font-medium">Credited from:</span>{" "}
                                    {row.equivalentCourseCode || "—"}
                                    {row.equivalentSourceSchool ? ` · ${row.equivalentSourceSchool}` : ""}
                                    {row.approvedCreditedUnitsOverride !== null
                                      ? ` · approved ${formatUnits(row.approvedCreditedUnitsOverride)} units`
                                      : ""}
                                  </span>
                                ) : null}
                                <input
                                  value={row.remarks ?? ""}
                                  onChange={(event) => patchRow(row.courseId, { remarks: event.target.value })}
                                  onBlur={() => {
                                    if (!isDirty) return;
                                    void saveRow(row.courseId).then((saved) => {
                                      if (saved) startTransition(() => router.refresh());
                                    });
                                  }}
                                  disabled={!canEdit}
                                  aria-label={`Remarks for ${row.courseCode}`}
                                  placeholder="Remarks…"
                                  maxLength={500}
                                  className={`${inputClass} mt-1 h-8 py-0 text-[12px]`}
                                />
                                {canEdit ? (
                                  <button
                                    type="button"
                                    onClick={() => setEquivalencyFor(row.courseId)}
                                    className="mt-1 text-[11px] font-medium text-brand-700 hover:underline"
                                  >
                                    Transfer / equivalency…
                                  </button>
                                ) : null}
                              </Td>
                            </tr>
                          );
                        })}
                      </tbody>
                    </TableShell>
                  ) : null}
                </section>
              );
            })
          )}
        </div>
      </Card>

      {!canEdit ? (
        <Callout tone="info">
          Your role can view assessments but not change them. Contact an encoder or administrator to record credits.
        </Callout>
      ) : null}

      {/* Status legend — colour is never the only signal */}
      <Card>
        <CardHeader title="How credit is counted" />
        <div className="flex flex-wrap gap-3 px-5 py-4 text-[12px] text-ink-600">
          {ASSESSMENT_STATUSES.map((status) => (
            <span key={status} className="inline-flex items-center gap-1.5">
              <AssessmentStatusBadge status={status} />
              <span>
                {status === "PASSED" || status === "CREDITED" ? "counts toward completion" : "does not count"}
              </span>
            </span>
          ))}
          <span className="w-full border-t border-ink-100 pt-3 text-[12px] leading-relaxed text-ink-500">
            Year-long subjects use the{" "}
            <strong className="text-ink-700">{yearLongPolicy === "ON_FINAL_PASS" ? "ON_FINAL_PASS" : "PER_COMPONENT"}</strong>{" "}
            policy for this curriculum.{" "}
            {yearLongPolicy === "ON_FINAL_PASS"
              ? "Credit for both semester components is released together once the final second-semester status is Passed or Credited. Neither component is ever counted twice."
              : "Each semester component is credited independently on its own status."}{" "}
            {allRows.filter((r) => r.isYearLong).length > 0
              ? `${allRows.filter((r) => r.isYearLong).length} of ${allRows.length} courses in this curriculum are year-long components.`
              : ""}
          </span>
        </div>
      </Card>

      {equivalencyRow ? (
        <EquivalencyDialog
          studentId={studentId}
          row={equivalencyRow}
          canApprove={canApproveEquivalency}
          onClose={() => setEquivalencyFor(null)}
          onSaved={(data) => {
            applySummary(data);
            setEquivalencyFor(null);
            startTransition(() => router.refresh());
          }}
        />
      ) : null}
    </div>
  );
}
