// ClaimCard837 — the warm-paper card that represents one 837P claim in
// the Upload page's streaming section. Originally inlined in
// `src/pages/Upload.tsx`; extracted into its own file in SP9 (June 2026)
// so the per-claim select-for-export interaction can live here without
// bloating the page.
//
// Two click targets, by design (see approach A in the batch-export
// design spec): a leading checkbox column for selection, and the rest
// of the card (a <button>) for expand/collapse. Putting the checkbox
// inside the button would be an a11y anti-pattern (nested interactive
// elements).

import { useMemo, useState } from "react";
import { useNavigate } from "react-router-dom";
import {
  AlertTriangle,
  ArrowRight,
  ChevronRight,
  XCircle,
} from "lucide-react";
import { Badge } from "@/components/ui/badge";
import { useAppStore } from "@/store";
import { fmt, toNum } from "@/lib/format";
import { cn } from "@/lib/utils";
import type { ClaimOutput, ServiceLine } from "@/types";
import { StatPill, ValidationDot } from "./ClaimCard/shared";

export interface ClaimCard837Props {
  claim: ClaimOutput;
  /**
   * Whether this card is currently selected for the batch export.
   * Controlled by the parent (Upload.tsx) via the per-claim checkbox.
   * The checkbox column only renders when the parent passes
   * `onToggleSelect` — keeps the component backward-compatible with
   * callers that don't need the export flow (e.g. the persisted
   * batch's "Recent batches" view, when we add it).
   */
  selected?: boolean;
  /** Called with the claim's id when the user clicks the checkbox. */
  onToggleSelect?: (claimId: string) => void;
}

export function ClaimCard837({ claim, selected = false, onToggleSelect }: ClaimCard837Props) {
  const [open, setOpen] = useState(false);
  const passed = claim.validation.passed;
  const hasWarnings = claim.validation.warnings.length > 0;
  // SP21 Phase 5 Task 5.7: a "See claim in detail →" link drills to
  // /claims?claim=ID — but ONLY when this streamed claim_id has
  // actually been persisted to a parsed batch. The Upload page
  // streams claims as the parser emits them; until the user clicks
  // "Save batch" the claim isn't visible to ClaimDrawer.
  const parsedBatches = useAppStore((s) => s.parsedBatches);
  const persistedClaimIds = useMemo(
    () => new Set(parsedBatches.flatMap((b) => b.claimIds)),
    [parsedBatches],
  );
  const canDrill = persistedClaimIds.has(claim.claim_id);
  const navigate = useNavigate();

  const showCheckbox = typeof onToggleSelect === "function";

  return (
    <div
      className="rounded-lg overflow-hidden border flex"
      style={{
        backgroundColor: "hsl(36 22% 96%)",
        borderColor: "hsl(30 14% 14% / 0.10)",
        boxShadow: "inset 0 1px 0 0 hsl(0 0% 100% / 0.5)",
      }}
    >
      {/* Selection column — only when the parent wires up selection. */}
      {showCheckbox ? (
        <label
          className="flex items-center pl-3 pr-2 cursor-pointer shrink-0"
          // Belt-and-suspenders: the label is a sibling of the button
          // below, so click events don't bubble into it. stopPropagation
          // here guards against future refactors that might nest the
          // label inside the button.
          onClick={(e) => e.stopPropagation()}
          data-testid={`claim-card-select-${claim.claim_id}`}
        >
          <input
            type="checkbox"
            checked={selected}
            onChange={() => onToggleSelect?.(claim.claim_id)}
            aria-label={`Select claim ${claim.claim_id} for export`}
            className="h-3.5 w-3.5 rounded border-border accent-accent cursor-pointer"
          />
        </label>
      ) : null}

      <button
        type="button"
        onClick={() => setOpen((v) => !v)}
        className={cn(
          "flex-1 min-w-0 text-left px-4 py-3 hover:bg-[hsl(36_22%_92%)] transition-colors",
          !showCheckbox && "rounded-l-lg",
        )}
        aria-expanded={open}
      >
        <div className="flex items-center gap-3">
          <ChevronRight
            className={cn(
              "h-3.5 w-3.5 transition-transform shrink-0",
              open && "rotate-90"
            )}
            strokeWidth={1.75}
            style={{ color: "hsl(var(--surface-ink-3))" }}
          />
          <div className="flex-1 min-w-0">
            <div className="flex items-center gap-2.5 flex-wrap">
              <span
                className="display mono text-[12.5px]"
                style={{ color: "hsl(var(--surface-ink))" }}
              >
                {claim.claim_id}
              </span>
              <span
                className="text-[12px] truncate"
                style={{ color: "hsl(var(--surface-ink-2))" }}
              >
                {claim.subscriber.first_name} {claim.subscriber.last_name}
              </span>
              <span
                className="text-[12px]"
                style={{ color: "hsl(var(--surface-ink-3))" }}
              >
                · {claim.payer.name}
              </span>
            </div>
            <div
              className="mono text-[10.5px] flex items-center gap-2 mt-1"
              style={{ color: "hsl(var(--surface-ink-3))" }}
            >
              <span>NPI {claim.billing_provider.npi}</span>
              <span className="opacity-40">·</span>
              <span>
                {claim.service_lines.length} line
                {claim.service_lines.length === 1 ? "" : "s"}
              </span>
              <span className="opacity-40">·</span>
              <span>{claim.diagnoses.length} dx</span>
            </div>
          </div>
          <div className="text-right shrink-0">
            <div
              className="display mono text-[14px]"
              style={{ color: "hsl(var(--surface-ink))" }}
            >
              {fmt.usdDecimal(claim.claim.total_charge)}
            </div>
            <div className="mt-0.5">
              <ValidationDot passed={passed} hasWarnings={hasWarnings} />
            </div>
          </div>
        </div>
      </button>
      {open ? (
        <div
          className="basis-full border-t px-4 py-3 grid gap-4 animate-fade-in"
          style={{
            borderColor: "hsl(30 14% 14% / 0.08)",
            backgroundColor: "hsl(36 22% 92%)",
          }}
        >
          <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
            <StatPill label="Member" value={claim.subscriber.member_id} />
            <StatPill
              label="Place of service"
              value={claim.claim.place_of_service ?? "—"}
            />
            <StatPill label="Frequency" value={claim.claim.frequency_code ?? "—"} />
            <StatPill
              label="Prior auth"
              value={claim.claim.prior_auth ?? "—"}
            />
          </div>

          {claim.diagnoses.length > 0 ? (
            <div>
              <div
                className="mono text-[10px] uppercase tracking-[0.18em] font-semibold mb-1.5"
                style={{ color: "hsl(var(--surface-ink-3))" }}
              >
                Diagnoses
              </div>
              <div className="flex flex-wrap gap-1.5">
                {claim.diagnoses.map((d, i) => (
                  <Badge key={`${d.code}-${i}`} variant="muted">
                    {d.qualifier ? `${d.qualifier}·` : ""}
                    {d.code}
                  </Badge>
                ))}
              </div>
            </div>
          ) : null}

          {claim.service_lines.length > 0 ? (
            <div>
              <div
                className="mono text-[10px] uppercase tracking-[0.18em] font-semibold mb-1.5"
                style={{ color: "hsl(var(--surface-ink-3))" }}
              >
                Service lines
              </div>
              <div
                className="rounded-md border overflow-x-auto"
                style={{
                  borderColor: "hsl(30 14% 14% / 0.10)",
                  backgroundColor: "hsl(36 22% 98%)",
                }}
              >
                <table className="w-full text-[12px]">
                  <thead style={{ backgroundColor: "hsl(36 22% 90%)" }}>
                    <tr className="text-left" style={{ color: "hsl(var(--surface-ink-2))" }}>
                      <th className="px-2.5 py-1.5 font-medium">#</th>
                      <th className="px-2.5 py-1.5 font-medium">Code</th>
                      <th className="px-2.5 py-1.5 font-medium">Mods</th>
                      <th className="px-2.5 py-1.5 font-medium">Date</th>
                      <th className="px-2.5 py-1.5 font-medium">Units</th>
                      <th className="px-2.5 py-1.5 font-medium text-right">Charge</th>
                    </tr>
                  </thead>
                  <tbody>
                    {claim.service_lines.map((line) => (
                      <ServiceLine837Row key={line.line_number} line={line} />
                    ))}
                  </tbody>
                </table>
              </div>
            </div>
          ) : null}

          {(claim.validation.errors.length > 0 ||
            claim.validation.warnings.length > 0) ? (
            <div>
              <div
                className="mono text-[10px] uppercase tracking-[0.18em] font-semibold mb-1.5"
                style={{ color: "hsl(var(--surface-ink-3))" }}
              >
                Validation
              </div>
              <ul className="space-y-1 text-[12px]">
                {claim.validation.errors.map((issue, i) => (
                  <li
                    key={`e-${i}`}
                    className="flex items-start gap-2 text-destructive"
                  >
                    <XCircle
                      className="h-3.5 w-3.5 mt-0.5 shrink-0"
                      strokeWidth={1.75}
                    />
                    <span>
                      <span className="mono">{issue.rule}</span> — {issue.message}
                    </span>
                  </li>
                ))}
                {claim.validation.warnings.map((issue, i) => (
                  <li
                    key={`w-${i}`}
                    className="flex items-start gap-2 text-[hsl(var(--warning))]"
                  >
                    <AlertTriangle
                      className="h-3.5 w-3.5 mt-0.5 shrink-0"
                      strokeWidth={1.75}
                    />
                    <span>
                      <span className="mono">{issue.rule}</span> — {issue.message}
                    </span>
                  </li>
                ))}
              </ul>
            </div>
          ) : null}

          {/* SP21 Phase 5 Task 5.7: drill to the persisted claim. Only
              renders when this streamed claim_id has been saved into
              a parsed batch (so ClaimDrawer can find it). Before
              "Save batch" the claim is streaming-only and the link
              would 404. */}
          {canDrill ? (
            <div className="pt-1">
              <button
                type="button"
                onClick={() =>
                  navigate(
                    `/claims?claim=${encodeURIComponent(claim.claim_id)}`,
                  )
                }
                data-testid="upload-claim-drill"
                aria-label={`See claim ${claim.claim_id} in detail`}
                className="inline-flex items-center gap-1.5 text-[12px] mono font-semibold cursor-pointer rounded-sm px-1 -mx-1 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1"
                style={{ color: "hsl(var(--surface-ink))" }}
              >
                See claim in detail
                <ArrowRight className="h-3 w-3" strokeWidth={2} />
              </button>
            </div>
          ) : null}
        </div>
      ) : null}
    </div>
  );
}

function ServiceLine837Row({ line }: { line: ServiceLine }) {
  return (
    <tr
      className="border-t"
      style={{ borderColor: "hsl(30 14% 14% / 0.08)" }}
    >
      <td
        className="px-2.5 py-1.5 mono"
        style={{ color: "hsl(var(--surface-ink))" }}
      >
        {line.line_number}
      </td>
      <td
        className="px-2.5 py-1.5 mono"
        style={{ color: "hsl(var(--surface-ink))" }}
      >
        {line.procedure.qualifier}·{line.procedure.code}
      </td>
      <td
        className="px-2.5 py-1.5 mono"
        style={{ color: "hsl(var(--surface-ink-3))" }}
      >
        {line.procedure.modifiers.length > 0
          ? line.procedure.modifiers.join(", ")
          : "—"}
      </td>
      <td
        className="px-2.5 py-1.5 mono"
        style={{ color: "hsl(var(--surface-ink-3))" }}
      >
        {line.service_date ?? "—"}
      </td>
      <td
        className="px-2.5 py-1.5 mono"
        style={{ color: "hsl(var(--surface-ink-3))" }}
      >
        {line.units ? `${toNum(line.units)} ${line.unit_type ?? ""}`.trim() : "—"}
      </td>
      <td
        className="px-2.5 py-1.5 mono text-right display"
        style={{ color: "hsl(var(--surface-ink))" }}
      >
        {fmt.usdDecimal(line.charge)}
      </td>
    </tr>
  );
}
