import { useState } from "react";
import { Download, X } from "lucide-react";
import { Badge, type BadgeProps } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { api } from "@/lib/api";
import { downloadTextFile } from "@/lib/download";
import { fmt } from "@/lib/format";
import { cn } from "@/lib/utils";
import type { ClaimDetail } from "@/types";

type ClaimDrawerHeaderProps = {
  claim: ClaimDetail;
  onClose: () => void;
  /**
   * Optional toast callback for surfacing download failures (network error,
   * 404 if the claim was deleted out from under us, 422 if the stored
   * payload can't be regenerated). Defaults to a no-op so consumers that
   * don't wire a toast still get the happy-path download.
   */
  onError?: (message: string) => void;
};

/**
 * State → Badge variant. The state machine value (see
 * `cyclone.db.ClaimState`) drives a color-coded chip so the user can
 * scan the drawer's status at a glance:
 *
 *   submitted  → secondary   (neutral, in-flight)
 *   accepted   → default     (brand-colored, accepted by payer)
 *   matched    → success     (paired with an ERA)
 *   paid       → success     (funds received)
 *   denied     → destructive (needs attention)
 *   pending    → warning     (waiting on something)
 *   anything else → muted
 */
const STATE_VARIANT: Record<string, BadgeProps["variant"]> = {
  submitted: "secondary",
  accepted: "default",
  matched: "success",
  paid: "success",
  denied: "destructive",
  pending: "warning",
};

function badgeVariantFor(state: string): BadgeProps["variant"] {
  return STATE_VARIANT[state] ?? "muted";
}

/**
 * Header band for the claim detail drawer (SP4).
 *
 * Top-left: instrument-style "Claim" eyebrow + large mono ID.
 * Top-right: state badge + total billed amount + close button. The
 * badge color encodes state so the user can read the drawer's status
 * at a glance without scrolling.
 */
export function ClaimDrawerHeader({
  claim,
  onClose,
  onError,
}: ClaimDrawerHeaderProps) {
  // Local "is downloading" flag so the button can show feedback while the
  // fetch is in flight. The header is rendered above the fold, so a stuck
  // spinner is the difference between "the click did something" and "did
  // my click even register?"
  const [downloading, setDownloading] = useState(false);

  async function handleDownload() {
    if (downloading) return;
    setDownloading(true);
    try {
      const { text, filename } = await api.serializeClaim837(claim.id);
      downloadTextFile(filename, "text/x12", text);
    } catch (err) {
      const message =
        err instanceof Error ? err.message : "Failed to download 837 file.";
      onError?.(message);
    } finally {
      setDownloading(false);
    }
  }

  return (
    <header
      className={cn(
        "flex items-start justify-between gap-4 px-6 py-5",
        "border-b border-[color:var(--m-border-heavy)]/40",
        "bg-[color:var(--m-surface)]"
      )}
      data-testid="claim-drawer-header"
    >
      {/* Left: eyebrow + mono claim ID */}
      <div className="flex flex-col gap-1 min-w-0">
        <span className="eyebrow text-[color:var(--m-ink-tertiary)]">
          Claim
        </span>
        <span
          data-testid="header-id"
          className="mono text-2xl font-semibold tracking-tight text-[color:var(--m-ink-primary)]"
        >
          {claim.id}
        </span>
      </div>

      {/* Right: state badge + total amount + download + close */}
      <div className="flex items-start gap-2">
        <div className="flex flex-col items-end gap-1">
          <Badge
            variant={badgeVariantFor(claim.state)}
            data-testid="header-state"
            className="uppercase tracking-[0.14em]"
          >
            {claim.stateLabel}
          </Badge>
          <span
            data-testid="header-amount"
            className="mono text-lg tabular-nums text-[color:var(--m-ink-primary)]"
          >
            {fmt.usdPrecise(claim.billedAmount)}
          </span>
        </div>
        <Button
          variant="ghost"
          size="icon"
          onClick={handleDownload}
          disabled={downloading}
          aria-label={downloading ? "Downloading 837 file" : "Download 837 file"}
          title="Download 837 file"
          data-testid="header-download-837"
        >
          <Download className="h-4 w-4" strokeWidth={1.75} />
        </Button>
        <Button
          variant="ghost"
          size="icon"
          onClick={onClose}
          aria-label="Close drawer"
          data-testid="header-close"
        >
          <X className="h-4 w-4" strokeWidth={1.75} />
        </Button>
      </div>
    </header>
  );
}
