import { useCallback, useMemo } from "react";
import { useSearchParams } from "react-router-dom";
import {
  AlertCircle,
  ArrowRight,
  CircleDashed,
  GitCompareArrows,
} from "lucide-react";
import { ApiError } from "@/lib/api";
import { Button } from "@/components/ui/button";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { EmptyState } from "@/components/ui/empty-state";
import { ErrorState } from "@/components/ui/error-state";
import {
  BatchDiffView,
  BatchDiffViewSkeleton,
} from "@/components/BatchDiffView";
import { RemitDrawer } from "@/components/RemitDrawer";
import { useBatches } from "@/hooks/useBatches";
import { useBatchDiff } from "@/hooks/useBatchDiff";
import { useRemitDrawerUrlState } from "@/hooks/useRemitDrawerUrlState";
import type { BatchSummary as ApiBatchSummary } from "@/lib/api";
import { cn } from "@/lib/utils";

// ---------------------------------------------------------------------------
// Inline URL state — uses react-router's useSearchParams so the page
// participates in the standard routing lifecycle (MemoryRouter in
// tests, BrowserRouter in production). `replace: true` keeps the
// picker tweaks from polluting the back-button stack.
// ---------------------------------------------------------------------------

function readIdsFromParams(params: URLSearchParams): {
  a: string | null;
  b: string | null;
} {
  const a = params.get("a");
  const b = params.get("b");
  return {
    a: a && a.length > 0 ? a : null,
    b: b && b.length > 0 ? b : null,
  };
}

// ---------------------------------------------------------------------------
// Kind badge — small inline label so the operator can spot which batch
// is which at a glance. Identical contract to the one in
// `BatchesList.tsx`; duplicated here because each lives inside a
// different page surface (the picker is part of this page, the row
// badge belongs to Batches).
// ---------------------------------------------------------------------------

function KindBadge({ kind }: { kind: ApiBatchSummary["kind"] }) {
  const cls =
    kind === "837p"
      ? "text-sky-300 border-sky-400/30 bg-sky-400/10"
      : "text-amber-300 border-amber-400/30 bg-amber-400/10";
  return (
    <span
      data-testid={`diff-picker-kind-${kind}`}
      className={cn(
        "inline-flex items-center gap-1 rounded-full border px-1.5 py-px text-[9.5px] font-semibold uppercase tracking-[0.14em] font-mono",
        cls,
      )}
    >
      {kind}
    </span>
  );
}

function BatchPicker({
  label,
  side,
  value,
  onChange,
  items,
  excludeId,
  testid,
}: {
  label: string;
  side: "A" | "B";
  value: string | null;
  onChange: (id: string) => void;
  items: ApiBatchSummary[];
  excludeId: string | null;
  testid: string;
}) {
  // Filter out the value already chosen on the *other* side so the
  // operator can't accidentally pick the same batch twice (which
  // produces a meaningless diff). Disabled rather than hidden so the
  // selection stays transparent.
  const visible = useMemo(
    () => items.filter((it) => it.id !== excludeId),
    [items, excludeId],
  );
  const selected = items.find((it) => it.id === value);
  const accent = side === "A" ? "hsl(212 100% 45%)" : "hsl(36 92% 50%)";
  const tint = side === "A" ? "hsl(212 85% 95%)" : "hsl(36 82% 92%)";
  return (
    <div
      className="rounded-xl border p-4 space-y-2"
      data-testid={testid}
      style={{
        backgroundColor: "hsl(36 22% 98%)",
        borderColor: "hsl(30 14% 14% / 0.10)",
        boxShadow:
          "inset 0 1px 0 0 hsl(0 0% 100% / 0.45), 0 1px 0 0 hsl(30 14% 22% / 0.06)",
      }}
    >
      <div
        aria-hidden
        className="absolute left-0 top-4 bottom-4 w-[3px] rounded-r-sm"
        style={{ backgroundColor: accent, opacity: 0.85 }}
      />
      <div className="flex items-center justify-between">
        <div className="flex items-center gap-2.5">
          <div
            aria-hidden
            className="h-5 w-5 rounded-md flex items-center justify-center mono font-semibold"
            style={{ backgroundColor: tint, color: accent, fontSize: 11 }}
          >
            {side}
          </div>
          <span
            className="mono text-[10.5px] uppercase tracking-[0.18em] font-semibold"
            style={{ color: "hsl(var(--surface-ink-3))" }}
          >
            {label}
          </span>
        </div>
        {selected ? (
          <span
            className="display tabular-nums text-[12.5px]"
            style={{ color: "hsl(var(--surface-ink-2))" }}
          >
            {selected.claimCount}{" "}
            <span
              className="mono not-italic uppercase tracking-[0.14em] text-[10px]"
              style={{ color: "hsl(var(--surface-ink-3))" }}
            >
              claims
            </span>
          </span>
        ) : null}
      </div>
      <Select value={value ?? ""} onValueChange={(v) => onChange(v)}>
        <SelectTrigger>
          {selected ? (
            <span className="flex items-center gap-2 truncate">
              <KindBadge kind={selected.kind} />
              <span className="font-mono num text-[12.5px]">{selected.id}</span>
              <span
                className="text-[12px] truncate"
                style={{ color: "hsl(var(--surface-ink-2))" }}
              >
                · {selected.inputFilename}
              </span>
            </span>
          ) : (
            <SelectValue placeholder="Pick a batch…" />
          )}
        </SelectTrigger>
        <SelectContent>
          {visible.length === 0 ? (
            <div className="px-3 py-2 text-xs text-muted-foreground">
              No other batches available.
            </div>
          ) : (
            visible.map((b) => (
              <SelectItem
                key={b.id}
                value={b.id}
                data-testid={`diff-picker-option-${b.id}`}
              >
                <span className="flex items-center gap-2">
                  <KindBadge kind={b.kind} />
                  <span className="font-mono num text-[12px]">{b.id}</span>
                  <span className="text-muted-foreground text-[12px] truncate">
                    · {b.inputFilename}
                  </span>
                </span>
              </SelectItem>
            ))
          )}
        </SelectContent>
      </Select>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Not-found branch — surfaces when the backend reports 404 for one of
// the picks. Most likely cause: a bookmark referencing a now-deleted
// batch, or another agent deleting between the picker load and the
// diff fetch.
// ---------------------------------------------------------------------------

function NotFoundState({
  a,
  b,
  onReset,
}: {
  a: string;
  b: string;
  onReset: () => void;
}) {
  return (
    <ErrorState
      message="One of these batches was not found."
      detail={`The backend couldn't find batch ${a} or ${b}. It may have been deleted between picker load and diff fetch.`}
      onRetry={onReset}
    />
  );
}

// ---------------------------------------------------------------------------
// Section header — § N + small italic vertical-rl label. Reused by
// both the picks and diff sections so the folio is uniform.
// ---------------------------------------------------------------------------

function Folio({ section, label, topClass = "top-7" }: {
  section: string;
  label: string;
  topClass?: string;
}) {
  return (
    <div
      aria-hidden
      className={cn(
        "absolute left-7 lg:left-12 flex flex-col items-center gap-1",
        topClass,
      )}
    >
      <span
        className="mono text-[10px] uppercase tracking-[0.18em] font-semibold"
        style={{ color: "hsl(var(--surface-ink-3))" }}
      >
        {section}
      </span>
      <div
        className="w-px h-10"
        style={{ backgroundColor: "hsl(30 14% 14% / 0.18)" }}
      />
      <span
        className="display italic"
        style={{
          color: "hsl(var(--surface-ink-2))",
          fontSize: 11,
          writingMode: "vertical-rl",
          transform: "rotate(180deg)",
          letterSpacing: "0.16em",
        }}
      >
        {label}
      </span>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Page
// ---------------------------------------------------------------------------

export function BatchDiff() {
  // URL → state via react-router. Keeps MemoryRouter (tests) and
  // BrowserRouter (production) symmetric: both update the
  // useSearchParams hook on every navigation.
  const [searchParams, setSearchParams] = useSearchParams();
  // SP21 Phase 4 Task 4.5: mount the RemitDrawer so a deep link to
  // /batch-diff?remit=REM-1 opens the drawer in-place. The BatchDiff
  // data model (BatchClaimDiffSummary) is a claim-level projection —
  // there are no per-remit IDs in the diff payload to wrap, so no
  // click-to-drill is wired here. The drawer still mounts so the
  // `?remit=` URL contract is honored when the user lands on this
  // page with the param set (e.g. from an external link).
  const { remitId, open, close } = useRemitDrawerUrlState();
  const { a, b } = useMemo(
    () => readIdsFromParams(searchParams),
    [searchParams],
  );

  const updateIds = useCallback(
    (next: { a: string | null; b: string | null }) => {
      const params = new URLSearchParams(searchParams);
      if (next.a === null) params.delete("a");
      else params.set("a", next.a);
      if (next.b === null) params.delete("b");
      else params.set("b", next.b);
      setSearchParams(params, { replace: true });
    },
    [searchParams, setSearchParams],
  );

  const setA = useCallback(
    (id: string) => updateIds({ a: id, b }),
    [b, updateIds],
  );
  const setB = useCallback(
    (id: string) => updateIds({ a, b: id }),
    [a, updateIds],
  );
  const reset = useCallback(() => updateIds({ a: null, b: null }), [updateIds]);

  const {
    data: batches,
    isLoading: loadingBatches,
    isError: batchesError,
    error: batchesErrorMsg,
    refetch: refetchBatches,
  } = useBatches(100);

  // Only fire the diff once both pickers have a value. The hook also
  // gates on this internally (defense-in-depth), so a half-picked URL
  // never hits the backend.
  const diff = useBatchDiff(a, b);
  const ready = a !== null && b !== null;

  // --- error / status derivation ------------------------------------
  const errKind: "network" | "not_found" | null = diff.error
    ? diff.error instanceof ApiError && diff.error.status === 404
      ? "not_found"
      : "network"
    : null;

  // -----------------------------------------------------------------
  // Stagger choreography
  // -----------------------------------------------------------------
  const heroDelay = 0;
  const foldDelay = 220;
  const titleDelay = 320;
  const picksDelay = 460;
  const diffDelay = 600;

  // --- render -------------------------------------------------------
  return (
    <div
      className="space-y-0 animate-fade-in"
      data-testid="batch-diff-page"
    >
      {/* =================================================================
          HERO — DARK EDITORIAL HEADER
          ================================================================= */}
      <section
        className="relative pt-6 pb-8 lg:pt-9 lg:pb-10"
        style={{ animationDelay: `${heroDelay}ms` }}
      >
        {/* Ghost "DIFF" watermark — a print-shop stamp behind the title. */}
        <div
          aria-hidden="true"
          className="pointer-events-none select-none absolute inset-x-0 top-[58%] -translate-y-1/2 whitespace-nowrap display text-center"
          style={{
            fontSize: "clamp(160px, 20vw, 300px)",
            letterSpacing: "-0.05em",
            opacity: 0.05,
            lineHeight: 1,
            color: "hsl(var(--surface-ink))",
          }}
        >
          DIFF
        </div>

        <div className="relative z-10 grid grid-cols-1 lg:grid-cols-[1fr,auto] gap-8 items-end mb-7">
          <div className="min-w-0 max-w-3xl">
            <div className="flex items-center gap-3 mb-5">
              <div className="h-px w-14 bg-foreground/25" />
              <span className="mono text-[12px] uppercase tracking-[0.22em] text-muted-foreground">
                Diff · Sheet 01
              </span>
              <span
                className="mono text-[12px] uppercase tracking-[0.22em] text-muted-foreground/60 hidden sm:inline"
                aria-hidden
              >
                · A vs B
              </span>
            </div>
            <h1 className="display text-[48px] sm:text-[64px] lg:text-[80px] leading-[0.92] text-foreground tracking-[-0.04em]">
              Compare{" "}
              <span className="italic text-muted-foreground/85">batches.</span>
            </h1>
          </div>
          <div className="flex flex-col items-start lg:items-end gap-3">
            <div className="inline-flex items-center gap-2 rounded-full border border-border/60 bg-card/60 px-3.5 py-2 text-[11.5px] mono uppercase tracking-[0.14em] text-muted-foreground backdrop-blur">
              <GitCompareArrows
                className="h-3.5 w-3.5"
                strokeWidth={1.75}
                style={{ color: "hsl(var(--accent))" }}
              />
              837P · 835 · first vs second
            </div>
            <kbd
              className="mono text-[10.5px] uppercase tracking-[0.18em] text-muted-foreground/70"
            >
              Pick a batch for each side
            </kbd>
          </div>
        </div>

        <div className="relative z-10 max-w-2xl">
          <p className="text-[14px] text-muted-foreground leading-relaxed">
            Pick two parsed batches — typically a submitted 837P and its
            corrected follow-up — and see what was added, removed, or changed
            between them.
          </p>
        </div>
      </section>

      {/* =================================================================
          FOLD — TORN PAGE
          ================================================================= */}
      <div
        aria-hidden
        className="relative h-14"
        style={{ animationDelay: `${foldDelay}ms` }}
      >
        <div
          className="absolute inset-x-0 top-0 h-1/2"
          style={{
            background:
              "linear-gradient(to bottom, hsl(0 0% 0% / 0.55), transparent)",
          }}
        />
        <div
          className="absolute inset-x-0 bottom-0 h-1/2"
          style={{
            background:
              "linear-gradient(to top, hsl(30 14% 14% / 0.18), transparent)",
          }}
        />
        <div
          className="absolute inset-x-0 top-1/2 -translate-y-1/2 h-px"
          style={{
            background:
              "linear-gradient(to right, transparent, hsl(30 14% 14% / 0.5) 12%, hsl(30 14% 14% / 0.7) 50%, hsl(30 14% 14% / 0.5) 88%, transparent)",
          }}
        />
        <div
          className="absolute inset-x-0 top-1/2 -translate-y-1/2 flex justify-between px-2"
          style={{ pointerEvents: "none" }}
        >
          {Array.from({ length: 48 }, (_, i) => (
            <span
              key={i}
              className="block h-[3px] w-[3px] rounded-full"
              style={{ backgroundColor: "hsl(30 14% 14% / 0.22)" }}
            />
          ))}
        </div>
        <div className="relative z-10 mx-auto h-full flex items-center justify-center gap-3 bg-background px-4 w-fit">
          <span
            className="display italic"
            style={{ color: "hsl(var(--muted-foreground))", fontSize: 15 }}
          >
            ↘
          </span>
          <span
            className="mono uppercase tracking-[0.24em]"
            style={{
              color: "hsl(var(--muted-foreground))",
              fontSize: 11,
              fontWeight: 500,
            }}
          >
            A → B
          </span>
          <span
            className="display italic"
            style={{ color: "hsl(var(--muted-foreground))", fontSize: 15 }}
          >
            ↙
          </span>
        </div>
      </div>

      {/* =================================================================
          PAPER PLANE
          ================================================================= */}
      <div
        className="relative max-w-[1280px] mx-auto"
        style={{
          animationDelay: `${titleDelay}ms`,
          backgroundColor: "hsl(var(--surface))",
          boxShadow:
            "inset 0 1px 0 0 hsl(0 0% 100% / 0.5), 0 1px 0 0 hsl(30 14% 22% / 0.06), 0 30px 80px -24px hsl(0 0% 0% / 0.45)",
        }}
      >
        {/* Paper grain */}
        <div
          aria-hidden
          className="pointer-events-none absolute inset-0 opacity-[0.04]"
          style={{
            backgroundImage:
              "url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.1  0 0 0 0 0.08  0 0 0 0 0.05  0 0 0 0.9 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>\")",
            backgroundSize: "160px 160px",
            mixBlendMode: "multiply",
          }}
        />

        {/* Title block */}
        <div
          className="relative px-8 lg:px-14 pt-12 pb-9 border-b animate-fade-in-up"
          style={{
            animationDelay: `${titleDelay}ms`,
            borderColor: "hsl(30 14% 14% / 0.12)",
          }}
        >
          <div
            aria-hidden
            className="absolute left-7 lg:left-12 top-0 bottom-0 w-px"
            style={{ backgroundColor: "hsl(30 14% 14% / 0.14)" }}
          />
          <div className="flex items-end justify-between gap-8 flex-wrap">
            <div>
              <div
                className="mono text-[12px] uppercase tracking-[0.24em] mb-4 font-medium"
                style={{ color: "hsl(var(--surface-ink-3))" }}
              >
                Sheet 01 · Compare two batches
              </div>
              <h2
                className="display leading-[0.92] tracking-[-0.04em]"
                style={{
                  color: "hsl(var(--surface-ink))",
                  fontSize: "clamp(48px, 7vw, 96px)",
                  fontWeight: 400,
                }}
              >
                Compare them.
              </h2>
              <div
                className="mt-4 display italic"
                style={{
                  color: "hsl(var(--surface-ink-2))",
                  fontSize: "clamp(15px, 1.3vw, 18px)",
                  lineHeight: 1.4,
                  maxWidth: "32ch",
                }}
              >
                Two picks, three buckets. What the second batch added, what
                the first batch dropped, and which claims moved between them.
              </div>
            </div>
            <div className="text-right shrink-0">
              <div
                className="mono text-[11px] uppercase tracking-[0.24em] mb-1.5 font-medium"
                style={{ color: "hsl(var(--surface-ink-3))" }}
              >
                On the wire
              </div>
              <div
                className="flex items-center justify-end gap-2 tabular-nums"
                style={{
                  color: "hsl(var(--surface-ink))",
                  fontSize: 26,
                  lineHeight: 1.1,
                }}
              >
                <span
                  className="display"
                  style={{ color: a ? "hsl(212 100% 45%)" : "hsl(var(--surface-ink-3))" }}
                >
                  {a ? "A" : "—"}
                </span>
                <ArrowRight
                  className="h-4 w-4 mt-0.5"
                  strokeWidth={1.5}
                  style={{ color: "hsl(var(--surface-ink-3))" }}
                />
                <span
                  className="display"
                  style={{ color: b ? "hsl(36 92% 50%)" : "hsl(var(--surface-ink-3))" }}
                >
                  {b ? "B" : "—"}
                </span>
              </div>
              <div
                className="mono text-[11px] mt-1"
                style={{ color: "hsl(var(--surface-ink-3))" }}
              >
                {ready ? "ready to diff" : "two picks needed"}
              </div>
            </div>
          </div>
        </div>

        {/* § 01 The picks */}
        <section
          aria-label="The picks"
          className="relative px-8 lg:px-14 py-7 animate-fade-in-up"
          style={{ animationDelay: `${picksDelay}ms` }}
        >
          <Folio section="§ 01" label="The picks" />
          <div
            className="pt-6 border-t"
            style={{
              borderTopStyle: "double",
              borderTopWidth: 3,
              borderColor: "hsl(30 14% 14% / 0.12)",
            }}
          >
            <div className="flex items-end justify-between gap-6 flex-wrap mb-5">
              <div>
                <div
                  className="mono text-[11.5px] uppercase tracking-[0.24em] font-semibold mb-2"
                  style={{ color: "hsl(var(--surface-ink-3))" }}
                >
                  The picks
                </div>
                <h3
                  className="display leading-[0.98] tracking-[-0.03em]"
                  style={{
                    color: "hsl(var(--surface-ink))",
                    fontSize: "clamp(24px, 2.6vw, 32px)",
                    fontWeight: 400,
                  }}
                >
                  One on each <span className="italic">side.</span>
                </h3>
              </div>
              <div
                className="text-[12.5px] display italic"
                style={{ color: "hsl(var(--surface-ink-2))", maxWidth: 380 }}
              >
                A is the "before" — B is the "after". A picked batch can't
                be picked again on the other side.
              </div>
            </div>
            <div className="relative grid grid-cols-1 md:grid-cols-2 gap-4">
              <BatchPicker
                label="A · left"
                side="A"
                value={a}
                onChange={setA}
                items={batches ?? []}
                excludeId={b}
                testid="diff-picker-a"
              />
              <BatchPicker
                label="B · right"
                side="B"
                value={b}
                onChange={setB}
                items={batches ?? []}
                excludeId={a}
                testid="diff-picker-b"
              />
            </div>
          </div>
        </section>

        {/* § 02 The diff */}
        <section
          aria-label="The diff"
          className="relative px-8 lg:px-14 pb-8 lg:pb-10 animate-fade-in-up"
          style={{ animationDelay: `${diffDelay}ms` }}
        >
          <Folio section="§ 02" label="The diff" topClass="top-9" />
          <div
            className="pt-6 border-t"
            style={{
              borderTopStyle: "double",
              borderTopWidth: 3,
              borderColor: "hsl(30 14% 14% / 0.12)",
            }}
          >
            <div className="flex items-end justify-between gap-6 flex-wrap mb-5">
              <div>
                <div
                  className="mono text-[11.5px] uppercase tracking-[0.24em] font-semibold mb-2"
                  style={{ color: "hsl(var(--surface-ink-3))" }}
                >
                  The diff
                </div>
                <h3
                  className="display leading-[0.98] tracking-[-0.03em]"
                  style={{
                    color: "hsl(var(--surface-ink))",
                    fontSize: "clamp(24px, 2.6vw, 32px)",
                    fontWeight: 400,
                  }}
                >
                  What <span className="italic">moved.</span>
                </h3>
              </div>
              {ready ? (
                <div
                  className="text-[12.5px] display italic"
                  style={{
                    color: "hsl(var(--surface-ink-2))",
                    maxWidth: 380,
                  }}
                >
                  Three buckets — added in B, removed from A, changed in
                  place. Unchanged claims are summarized but not listed.
                </div>
              ) : null}
            </div>

            {batchesError ? (
              <div
                className="rounded-md border p-5"
                style={{
                  borderColor: "hsl(30 14% 14% / 0.16)",
                  backgroundColor: "hsl(36 22% 96%)",
                }}
              >
                <ErrorState
                  message="Couldn't load batches from the backend."
                  detail={
                    batchesErrorMsg instanceof Error
                      ? batchesErrorMsg.message
                      : String(batchesErrorMsg)
                  }
                  onRetry={() => refetchBatches()}
                />
              </div>
            ) : !ready ? (
              <div
                className="rounded-md border p-12 text-center"
                style={{
                  borderColor: "hsl(30 14% 14% / 0.16)",
                  borderStyle: "dashed",
                  backgroundColor: "hsl(36 22% 96%)",
                }}
                data-testid="batch-diff-awaiting"
              >
                <EmptyState
                  icon={
                    <GitCompareArrows
                      className="h-4 w-4"
                      strokeWidth={1.5}
                    />
                  }
                  eyebrow="Batch diff · awaiting picks"
                  message="Choose one batch for A and one for B to compute the diff."
                />
              </div>
            ) : loadingBatches ? (
              <BatchDiffViewSkeleton />
            ) : errKind === "not_found" ? (
              <NotFoundState a={a as string} b={b as string} onReset={reset} />
            ) : diff.isError ? (
              <div
                className="rounded-md border p-5"
                style={{
                  borderColor: "hsl(30 14% 14% / 0.16)",
                  backgroundColor: "hsl(36 22% 96%)",
                }}
              >
                <ErrorState
                  message="Couldn't compute the diff between these two batches."
                  detail={
                    diff.error instanceof Error
                      ? diff.error.message
                      : String(diff.error)
                  }
                  onRetry={() => diff.refetch()}
                />
              </div>
            ) : diff.isLoading || !diff.data ? (
              <BatchDiffViewSkeleton />
            ) : (
              <BatchDiffView data={diff.data} />
            )}
          </div>
        </section>

        {/* Action footer — always visible when ready so the operator can
            clear or force-refresh without scrolling back to the picker. */}
        {ready ? (
          <div
            className="relative px-8 lg:px-14 py-5 border-t flex items-center justify-between gap-3 flex-wrap"
            style={{
              borderColor: "hsl(30 14% 14% / 0.12)",
            }}
          >
            <div
              className="text-[12.5px] display italic"
              style={{ color: "hsl(var(--surface-ink-2))" }}
            >
              {diff.isFetching ? (
                <span className="inline-flex items-center gap-1.5">
                  <CircleDashed
                    className="h-3 w-3 animate-spin"
                    strokeWidth={1.75}
                  />
                  Refreshing…
                </span>
              ) : (
                <>
                  Comparing{" "}
                  <span
                    className="display mono not-italic"
                    style={{ color: "hsl(var(--surface-ink))" }}
                  >
                    {a}
                  </span>{" "}
                  with{" "}
                  <span
                    className="display mono not-italic"
                    style={{ color: "hsl(var(--surface-ink))" }}
                  >
                    {b}
                  </span>
                  .
                </>
              )}
            </div>
            <div className="flex items-center gap-2 flex-wrap">
              <Button
                variant="outline"
                size="sm"
                onClick={() => diff.refetch()}
                data-testid="diff-refresh-button"
              >
                Refresh
              </Button>
              <Button
                variant="ghost"
                size="sm"
                onClick={reset}
                data-testid="diff-clear-button"
              >
                <AlertCircle className="h-3.5 w-3.5 mr-1" strokeWidth={1.75} />
                Clear picks
              </Button>
            </div>
          </div>
        ) : null}

        {/* Footer */}
        <div
          className="relative px-8 lg:px-14 py-5 border-t flex items-center justify-between mono text-[10.5px] uppercase tracking-[0.18em]"
          style={{
            borderColor: "hsl(30 14% 14% / 0.12)",
            color: "hsl(var(--surface-ink-3))",
          }}
        >
          <span>End of sheet 01</span>
          <span>Cyclone · Batch diff</span>
          <span>{ready ? "A vs B" : "awaiting picks"}</span>
        </div>
      </div>

      {/* SP21 Phase 4 Task 4.5: RemitDrawer mount. There are no
          per-remit rows in the diff payload (the page is a
          claim-level projection), so this drawer is for deep-link
          support only — clicking a claim row does not open it.
          When the user lands on /batch-diff?remit=REM-1, the drawer
          opens in-place. The `remits` list is empty so j/k is a
          no-op while the drawer is open. */}
      <RemitDrawer
        remitId={remitId}
        remits={[]}
        onClose={close}
        onNavigate={open}
        onToggleHelp={() => {
          // BatchDiff has no cheatsheet surface; `?` is a no-op
          // here, but the prop is required by the drawer's contract.
        }}
      />
    </div>
  );
}
