import { Plus, Minus, Equal, ArrowRight, 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 { KpiCard } from "@/components/KpiCard";
import { fmt } from "@/lib/format";
import { cn } from "@/lib/utils";
import type {
  BatchDiff,
  BatchDiffChangedRow,
  BatchDiffSideMeta,
  BatchDiffSummary,
  BatchClaimDiffSummary,
} from "@/types";

// ---------------------------------------------------------------------------
// Side meta header — small panel identifying which batch is on the left / right.
// ---------------------------------------------------------------------------

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="surface rounded-xl p-4 flex flex-col gap-2"
      data-testid={`batch-diff-side-${label.toLowerCase()}`}
    >
      <div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">
        {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]">{side.id}</span>
      </div>
      <div className="font-mono text-[12px] text-muted-foreground truncate">
        {side.inputFilename}
      </div>
      <div className="flex items-center justify-between text-xs text-muted-foreground">
        <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.
// ---------------------------------------------------------------------------

function SummaryCards({ summary }: { summary: BatchDiffSummary }) {
  return (
    <div className="grid grid-cols-2 md:grid-cols-4 gap-3" data-testid="batch-diff-summary">
      <KpiCard
        label="Added in B"
        value={fmt.num(summary.addedCount)}
        icon={Plus}
        hint="In B, not in A"
      />
      <KpiCard
        label="Removed from A"
        value={fmt.num(summary.removedCount)}
        icon={Minus}
        hint="In A, not in B"
      />
      <KpiCard
        label="Changed"
        value={fmt.num(summary.changedCount)}
        icon={Equal}
        hint="Deltas in either side"
      />
      <KpiCard
        label="Unchanged"
        value={fmt.num(summary.unchangedCount)}
        icon={Equal}
        hint="Identical across A & B"
      />
    </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-muted-foreground/60 text-[12px]">—</span>;
  }
  return <span className="text-[13px]">{name}</span>;
}

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

function DateCell({ value }: { value: string | null }) {
  if (!value) {
    return <span className="text-muted-foreground/60 text-[12px]">—</span>;
  }
  return <span className="num text-[12.5px]">{value}</span>;
}

function StatusCell({ value }: { value: string }) {
  if (!value) {
    return <span className="text-muted-foreground/60 text-[12px]">—</span>;
  }
  return (
    <Badge
      variant="outline"
      className="font-mono uppercase tracking-wider text-[10px]"
    >
      {value}
    </Badge>
  );
}

function CptCell({ codes }: { codes: string[] }) {
  if (!codes || codes.length === 0) {
    return <span className="text-muted-foreground/60 text-[12px]">—</span>;
  }
  return (
    <span className="font-mono text-[11.5px] tracking-tight">
      {codes.join(", ")}
    </span>
  );
}

// ---------------------------------------------------------------------------
// Section tables — one per bucket (added / removed / changed).
// ---------------------------------------------------------------------------

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] text-muted-foreground mb-0.5">
            {eyebrow}
          </div>
          <h2 className="text-[15px] font-semibold tracking-tight">{title}</h2>
        </div>
        <span className="font-mono num text-[12.5px] text-muted-foreground">
          {fmt.num(count)}
        </span>
      </header>
      {count === 0 ? (
        <div
          className="surface rounded-xl border border-dashed border-border/60 p-6 text-center text-[12.5px] text-muted-foreground"
          data-testid={`${testid}-empty`}
        >
          {emptyMessage}
        </div>
      ) : (
        <div className="surface rounded-xl overflow-hidden">
          <Table>
            <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.
// ---------------------------------------------------------------------------

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="surface rounded-xl border border-dashed border-border/60 p-10 text-center">
        <div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-1.5">
          Diff · no deltas
        </div>
        <div className="text-[13.5px] text-muted-foreground">
          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>
  );
}
