import {
  ArrowRight,
  Equal,
  Minus,
  Plus,
  type LucideIcon,
} from "lucide-react";
import { Badge } from "@/components/ui/badge";
import { Skeleton } from "@/components/ui/skeleton";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { fmt } from "@/lib/format";
import { cn } from "@/lib/utils";
import type {
  BatchClaimDiffSummary,
  BatchDiff,
  BatchDiffChangedRow,
  BatchDiffSideMeta,
  BatchDiffSummary,
} from "@/types";

// ---------------------------------------------------------------------------
// Side meta header — small panel identifying which batch is on the
// left / right. Paper-toned to sit inside the cream "paper plane" of
// the BatchDiff page. data-testid pinned by BatchDiff.test.tsx.
// ---------------------------------------------------------------------------

function SideMeta({
  side,
  label,
}: {
  side: BatchDiffSideMeta;
  label: string;
}) {
  // Color mirrors the BatchesList kind badge so the visual identity is
  // consistent across the app: 837p in cool blue, 835 in warm amber.
  const kindClass =
    side.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 (
    <div
      className="rounded-xl p-4 flex flex-col gap-2 border"
      data-testid={`batch-diff-side-${label.toLowerCase()}`}
      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
        className="text-[10.5px] font-semibold uppercase tracking-[0.18em]"
        style={{ color: "hsl(var(--surface-ink-3))" }}
      >
        {label}
      </div>
      <div className="flex items-center gap-2">
        <span
          className={cn(
            "inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-[10.5px] font-semibold uppercase tracking-[0.14em] font-mono",
            kindClass,
          )}
        >
          {side.kind}
        </span>
        <span
          className="display num text-[13px]"
          style={{ color: "hsl(var(--surface-ink))" }}
        >
          {side.id}
        </span>
      </div>
      <div
        className="font-mono text-[12px] truncate"
        style={{ color: "hsl(var(--surface-ink-2))" }}
      >
        {side.inputFilename}
      </div>
      <div
        className="flex items-center justify-between text-xs"
        style={{ color: "hsl(var(--surface-ink-3))" }}
      >
        <span>Parsed {side.parsedAt ? fmt.dateShort(side.parsedAt) : "—"}</span>
        <span className="font-mono num">
          {fmt.num(side.claimCount)} claim{side.claimCount === 1 ? "" : "s"}
        </span>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Summary cards — the four-count tile row. Paper-toned via
// DiffKpiTile so the counts sit naturally on the cream paper plane.
// ---------------------------------------------------------------------------

function SummaryCards({ summary }: { summary: BatchDiffSummary }) {
  return (
    <div
      className="grid grid-cols-2 md:grid-cols-4 gap-3"
      data-testid="batch-diff-summary"
    >
      <DiffKpiTile
        label="Added in B"
        value={fmt.num(summary.addedCount)}
        icon={Plus}
        hint="In B, not in A"
        tone="success"
      />
      <DiffKpiTile
        label="Removed from A"
        value={fmt.num(summary.removedCount)}
        icon={Minus}
        hint="In A, not in B"
        tone="destructive"
      />
      <DiffKpiTile
        label="Changed"
        value={fmt.num(summary.changedCount)}
        icon={Equal}
        hint="Deltas in either side"
        tone="amber"
      />
      <DiffKpiTile
        label="Unchanged"
        value={fmt.num(summary.unchangedCount)}
        icon={Equal}
        hint="Identical across A & B"
        tone="ink"
      />
    </div>
  );
}

// ---------------------------------------------------------------------------
// DiffKpiTile — paper-toned metric tile for the diff summary row.
// Mirrors AckKpiTile / BatchesKpiTile from the other hybrid pages.
// ---------------------------------------------------------------------------

function DiffKpiTile({
  label,
  value,
  icon: Icon,
  hint,
  tone,
}: {
  label: string;
  value: string;
  icon: LucideIcon;
  hint: string;
  tone: "success" | "destructive" | "amber" | "ink";
}) {
  const accentMap = {
    success: "hsl(152 64% 38%)",
    destructive: "hsl(358 70% 42%)",
    amber: "hsl(36 92% 50%)",
    ink: "hsl(var(--surface-ink))",
  } as const;
  const tintMap = {
    success: "hsl(152 50% 88%)",
    destructive: "hsl(358 70% 92%)",
    amber: "hsl(36 82% 92%)",
    ink: "hsl(36 22% 90%)",
  } as const;
  const accent = accentMap[tone];
  const tint = tintMap[tone];
  return (
    <div
      className="relative rounded-xl p-4 overflow-hidden border"
      title={hint}
      style={{
        backgroundColor: "hsl(var(--surface))",
        boxShadow:
          "inset 0 1px 0 0 hsl(0 0% 100% / 0.45), 0 1px 0 0 hsl(30 14% 22% / 0.06), inset 3px 0 0 0 hsl(0 0% 100% / 0.4)",
        borderColor: "hsl(30 14% 14% / 0.10)",
      }}
    >
      <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 mb-2">
        <div
          className="mono text-[10px] uppercase tracking-[0.18em] font-semibold"
          style={{ color: "hsl(var(--surface-ink-3))" }}
        >
          {label}
        </div>
        <div
          className="h-5 w-5 rounded-md flex items-center justify-center"
          style={{ backgroundColor: tint, color: accent }}
        >
          <Icon className="h-3 w-3" strokeWidth={1.75} />
        </div>
      </div>
      <div
        className="display tabular-nums tracking-[-0.04em]"
        style={{
          color: "hsl(var(--surface-ink))",
          fontSize: "clamp(26px, 2.8vw, 36px)",
          lineHeight: 1,
          fontWeight: 400,
        }}
      >
        {value}
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Row indicator — `+` / `-` / `~` gutter on the left of every row.
// ---------------------------------------------------------------------------

function RowIndicator({
  kind,
}: {
  kind: "added" | "removed" | "changed";
}) {
  const cfg = {
    added: {
      Icon: Plus,
      cls: "text-[hsl(var(--success))] bg-[hsl(var(--success)/0.10)] border-[hsl(var(--success)/0.30)]",
      label: "added",
    },
    removed: {
      Icon: Minus,
      cls: "text-destructive bg-destructive/10 border-destructive/30",
      label: "removed",
    },
    changed: {
      Icon: ArrowRight,
      cls: "text-[hsl(var(--warning))] bg-[hsl(var(--warning)/0.10)] border-[hsl(var(--warning)/0.30)]",
      label: "changed",
    },
  }[kind];
  const Icon: LucideIcon = cfg.Icon;
  return (
    <span
      aria-label={cfg.label}
      data-testid={`diff-indicator-${kind}`}
      className={cn(
        "inline-flex h-5 w-5 items-center justify-center rounded border font-mono text-[11px]",
        cfg.cls,
      )}
    >
      <Icon className="h-3 w-3" strokeWidth={2.25} />
    </span>
  );
}

// ---------------------------------------------------------------------------
// Cell renderers for the summary columns. Kept tiny — these are
// hairline cells in a tabular diff, not full claim cards.
// ---------------------------------------------------------------------------

function ClaimIdCell({ id }: { id: string }) {
  return (
    <span
      className="font-mono text-[12px] tracking-tight"
      data-testid="diff-claim-id"
    >
      {id}
    </span>
  );
}

function PatientCell({ name }: { name: string }) {
  if (!name) {
    return (
      <span
        className="text-[12px]"
        style={{ color: "hsl(var(--surface-ink-3))" }}
      >
        —
      </span>
    );
  }
  return (
    <span
      className="text-[13px]"
      style={{ color: "hsl(var(--surface-ink))" }}
    >
      {name}
    </span>
  );
}

function ChargeCell({ value }: { value: number }) {
  return (
    <span
      className="display num text-[13px] tabular-nums"
      style={{ color: "hsl(var(--surface-ink))" }}
    >
      {fmt.usdPrecise(value)}
    </span>
  );
}

function DateCell({ value }: { value: string | null }) {
  if (!value) {
    return (
      <span
        className="text-[12px]"
        style={{ color: "hsl(var(--surface-ink-3))" }}
      >
        —
      </span>
    );
  }
  return (
    <span
      className="num text-[12.5px]"
      style={{ color: "hsl(var(--surface-ink-2))" }}
    >
      {value}
    </span>
  );
}

function StatusCell({ value }: { value: string }) {
  if (!value) {
    return (
      <span
        className="text-[12px]"
        style={{ color: "hsl(var(--surface-ink-3))" }}
      >
        —
      </span>
    );
  }
  return (
    <Badge
      variant="outline"
      className="font-mono uppercase tracking-wider text-[10px]"
      style={{
        color: "hsl(var(--surface-ink))",
        borderColor: "hsl(30 14% 14% / 0.20)",
      }}
    >
      {value}
    </Badge>
  );
}

function CptCell({ codes }: { codes: string[] }) {
  if (!codes || codes.length === 0) {
    return (
      <span
        className="text-[12px]"
        style={{ color: "hsl(var(--surface-ink-3))" }}
      >
        —
      </span>
    );
  }
  return (
    <span
      className="font-mono text-[11.5px] tracking-tight"
      style={{ color: "hsl(var(--surface-ink-2))" }}
    >
      {codes.join(", ")}
    </span>
  );
}

// ---------------------------------------------------------------------------
// Section tables — one per bucket (added / removed / changed). Uses
// `tone="paper"` so the table chrome matches the cream paper plane.
// ---------------------------------------------------------------------------

type Side = "a" | "b";

function summaryCells(summary: BatchClaimDiffSummary, side: Side) {
  // Single-row builder that keeps the column order consistent across
  // all three buckets. ``side`` is just a key for the testid so
  // tests can target a specific cell.
  return {
    claimId: <ClaimIdCell id={summary.claim_id} />,
    patient: <PatientCell name={summary.patient_name} />,
    charge: <ChargeCell value={summary.total_charge} />,
    serviceDate: <DateCell value={summary.service_date} />,
    status: <StatusCell value={summary.status} />,
    cpt: <CptCell codes={summary.cpt_codes} />,
    // Suppress an unused-param warning while leaving the key in the
    // object for readability / future use.
    _side: side,
  };
}

function SummaryRow({
  summary,
  indicator,
  testid,
}: {
  summary: BatchClaimDiffSummary;
  indicator: "added" | "removed";
  testid: string;
}) {
  const cells = summaryCells(summary, indicator === "added" ? "b" : "a");
  return (
    <TableRow data-testid={testid} className="animate-row-flash">
      <TableCell className="w-10">
        <RowIndicator kind={indicator} />
      </TableCell>
      <TableCell>{cells.claimId}</TableCell>
      <TableCell>{cells.patient}</TableCell>
      <TableCell className="text-right">{cells.charge}</TableCell>
      <TableCell>{cells.serviceDate}</TableCell>
      <TableCell>{cells.status}</TableCell>
      <TableCell>{cells.cpt}</TableCell>
    </TableRow>
  );
}

function ChangedRowView({
  row,
  testid,
}: {
  row: BatchDiffChangedRow;
  testid: string;
}) {
  const a = row.a;
  const b = row.b;
  const changedFields = new Set(row.diff.map((d) => d.field));
  return (
    <TableRow data-testid={testid} className="animate-row-flash">
      <TableCell className="w-10">
        <RowIndicator kind="changed" />
      </TableCell>
      <TableCell>
        <ClaimIdCell id={a.claim_id} />
      </TableCell>
      <TableCell>
        <div className="flex flex-col gap-0.5">
          <span
            className={cn(
              "text-[12.5px]",
              a.patient_name !== b.patient_name
                ? "line-through text-muted-foreground/70"
                : "",
            )}
          >
            {a.patient_name || "—"}
          </span>
          {a.patient_name !== b.patient_name ? (
            <span className="text-[12.5px] text-[hsl(var(--warning))]">
              {b.patient_name || "—"}
            </span>
          ) : null}
        </div>
      </TableCell>
      <TableCell className="text-right">
        <div className="flex flex-col items-end gap-0.5">
          <span
            className={cn(
              "display num text-[13px] tabular-nums",
              changedFields.has("total_charge")
                ? "line-through text-muted-foreground/70"
                : "",
            )}
          >
            {fmt.usdPrecise(a.total_charge)}
          </span>
          {changedFields.has("total_charge") ? (
            <span className="display num text-[13px] tabular-nums text-[hsl(var(--warning))]">
              {fmt.usdPrecise(b.total_charge)}
            </span>
          ) : null}
        </div>
      </TableCell>
      <TableCell>
        <div className="flex flex-col gap-0.5">
          <span
            className={cn(
              "num text-[12.5px]",
              changedFields.has("service_date")
                ? "line-through text-muted-foreground/70"
                : "",
            )}
          >
            {a.service_date || "—"}
          </span>
          {changedFields.has("service_date") ? (
            <span className="num text-[12.5px] text-[hsl(var(--warning))]">
              {b.service_date || "—"}
            </span>
          ) : null}
        </div>
      </TableCell>
      <TableCell>
        <div className="flex flex-col gap-0.5">
          <span
            className={cn(
              changedFields.has("status")
                ? "line-through text-muted-foreground/70"
                : "",
            )}
          >
            <StatusCell value={a.status} />
          </span>
          {changedFields.has("status") ? (
            <StatusCell value={b.status} />
          ) : null}
        </div>
      </TableCell>
      <TableCell>
        <div className="flex flex-col gap-0.5">
          <span
            className={cn(
              "font-mono text-[11.5px] tracking-tight",
              changedFields.has("cpt_codes")
                ? "line-through text-muted-foreground/70"
                : "",
            )}
          >
            {a.cpt_codes.length === 0 ? "—" : a.cpt_codes.join(", ")}
          </span>
          {changedFields.has("cpt_codes") ? (
            <span className="font-mono text-[11.5px] tracking-tight text-[hsl(var(--warning))]">
              {b.cpt_codes.length === 0 ? "—" : b.cpt_codes.join(", ")}
            </span>
          ) : null}
        </div>
      </TableCell>
    </TableRow>
  );
}

function SectionTable({
  title,
  eyebrow,
  count,
  children,
  testid,
  emptyMessage,
}: {
  title: string;
  eyebrow: string;
  count: number;
  children: React.ReactNode;
  testid: string;
  emptyMessage: string;
}) {
  return (
    <section className="space-y-3" data-testid={testid}>
      <header className="flex items-baseline justify-between">
        <div>
          <div
            className="text-[10.5px] font-semibold uppercase tracking-[0.18em] mb-0.5"
            style={{ color: "hsl(var(--surface-ink-3))" }}
          >
            {eyebrow}
          </div>
          <h3
            className="display leading-[0.98] tracking-[-0.03em]"
            style={{
              color: "hsl(var(--surface-ink))",
              fontSize: "clamp(20px, 2.2vw, 26px)",
              fontWeight: 400,
            }}
          >
            {title}
          </h3>
        </div>
        <span
          className="font-mono num text-[12.5px]"
          style={{ color: "hsl(var(--surface-ink-3))" }}
        >
          {fmt.num(count)}
        </span>
      </header>
      {count === 0 ? (
        <div
          className="rounded-xl border p-6 text-center text-[12.5px]"
          data-testid={`${testid}-empty`}
          style={{
            borderColor: "hsl(30 14% 14% / 0.16)",
            borderStyle: "dashed",
            backgroundColor: "hsl(36 22% 96%)",
            color: "hsl(var(--surface-ink-3))",
          }}
        >
          {emptyMessage}
        </div>
      ) : (
        <div
          className="rounded-xl border overflow-hidden"
          style={{
            borderColor: "hsl(30 14% 14% / 0.10)",
            backgroundColor: "hsl(36 22% 98%)",
            boxShadow: "inset 0 1px 0 0 hsl(0 0% 100% / 0.5)",
          }}
        >
          <Table tone="paper">
            <TableHeader>
              <TableRow>
                <TableHead className="w-10" aria-label="Diff indicator" />
                <TableHead>Claim ID</TableHead>
                <TableHead>Patient</TableHead>
                <TableHead className="text-right">Charge</TableHead>
                <TableHead>Service date</TableHead>
                <TableHead>Status</TableHead>
                <TableHead>CPT</TableHead>
              </TableRow>
            </TableHeader>
            <TableBody>{children}</TableBody>
          </Table>
        </div>
      )}
    </section>
  );
}

// ---------------------------------------------------------------------------
// Skeleton — used by the page while the diff is loading. Paper-toned
// (cream blocks) to match the paper plane chrome.
// ---------------------------------------------------------------------------

export function BatchDiffViewSkeleton() {
  return (
    <div className="space-y-6" data-testid="batch-diff-skeleton">
      <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
        <Skeleton variant="default" height={92} />
        <Skeleton variant="default" height={92} />
      </div>
      <div className="grid grid-cols-2 md:grid-cols-4 gap-3">
        {Array.from({ length: 4 }).map((_, i) => (
          <Skeleton key={i} variant="default" height={92} />
        ))}
      </div>
      {Array.from({ length: 3 }).map((_, i) => (
        <Skeleton key={i} variant="default" height={220} />
      ))}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Empty state — both batches selected but no deltas.
// ---------------------------------------------------------------------------

export function BatchDiffEmpty({ data }: { data: BatchDiff }) {
  return (
    <div
      className="space-y-6"
      data-testid="batch-diff-empty"
    >
      <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
        <SideMeta side={data.a} label="A (left)" />
        <SideMeta side={data.b} label="B (right)" />
      </div>
      <SummaryCards summary={data.summary} />
      <div
        className="rounded-xl border p-10 text-center"
        style={{
          borderColor: "hsl(30 14% 14% / 0.16)",
          borderStyle: "dashed",
          backgroundColor: "hsl(36 22% 96%)",
        }}
      >
        <div
          className="text-[10.5px] font-semibold uppercase tracking-[0.18em] mb-1.5"
          style={{ color: "hsl(var(--surface-ink-3))" }}
        >
          Diff · no deltas
        </div>
        <div
          className="text-[13.5px]"
          style={{ color: "hsl(var(--surface-ink-2))" }}
        >
          These two batches are identical — no claims added, removed, or
          changed between A and B.
        </div>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Main view — rendered once both batches are picked and the diff returns.
// ---------------------------------------------------------------------------

export function BatchDiffView({ data }: { data: BatchDiff }) {
  const { a, b, added, removed, changed, summary } = data;
  const allEmpty =
    summary.addedCount === 0 &&
    summary.removedCount === 0 &&
    summary.changedCount === 0;
  if (allEmpty) {
    return <BatchDiffEmpty data={data} />;
  }
  return (
    <div className="space-y-6" data-testid="batch-diff-view">
      <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
        <SideMeta side={a} label="A (left)" />
        <SideMeta side={b} label="B (right)" />
      </div>
      <SummaryCards summary={summary} />
      <SectionTable
        title="Added in B"
        eyebrow="Diff · additions"
        count={added.length}
        testid="batch-diff-added-section"
        emptyMessage="No claims were added in B."
      >
        {added.map((row, idx) => (
          <SummaryRow
            key={`${row.claim_id}-${idx}`}
            summary={row}
            indicator="added"
            testid={`diff-added-row-${row.claim_id}`}
          />
        ))}
      </SectionTable>
      <SectionTable
        title="Removed from A"
        eyebrow="Diff · removals"
        count={removed.length}
        testid="batch-diff-removed-section"
        emptyMessage="No claims were removed from A."
      >
        {removed.map((row, idx) => (
          <SummaryRow
            key={`${row.claim_id}-${idx}`}
            summary={row}
            indicator="removed"
            testid={`diff-removed-row-${row.claim_id}`}
          />
        ))}
      </SectionTable>
      <SectionTable
        title="Changed"
        eyebrow="Diff · mutations"
        count={changed.length}
        testid="batch-diff-changed-section"
        emptyMessage="No claims were changed between A and B."
      >
        {changed.map((row, idx) => (
          <ChangedRowView
            key={`${row.a.claim_id}-${idx}`}
            row={row}
            testid={`diff-changed-row-${row.a.claim_id}`}
          />
        ))}
      </SectionTable>
    </div>
  );
}
