import * as React from "react";

import { cn } from "@/lib/utils";

/**
 * One label–value pair. `value` null/undefined/"" reads "—" with "Not recorded" for screen readers (never
 * blank). `money` keeps the value on one line. Pairs a role can't see are simply not passed in; the grid
 * closes up (P3, PS-04, CU-08).
 */
export type DescItem = { label: string; value?: React.ReactNode; money?: boolean; action?: React.ReactNode; span?: 1 | 2 | 3 | 4 };

function Value({ item }: { item: DescItem }) {
  const empty = item.value == null || item.value === "";
  if (empty) {
    return (
      <>
        <span aria-hidden>—</span>
        <span className="sr-only">Not recorded</span>
      </>
    );
  }
  return <span className={cn(item.money && "whitespace-nowrap tabular-nums")}>{item.value}</span>;
}

/**
 * Description list (spec 02 §7): one record's attributes as label–value pairs, read-only.
 * - `stacked`: label above value in 2–4 columns (profile headers).
 * - `inline`: label left (about a third), value right, divided rows (drawers, narrow panels).
 * - `summary`: inline with the last item emphasised and right-aligned figures (confirmation summaries).
 * `loading` keeps the labels and shows skeleton values. `onGrey` uses the stronger label colour.
 */
export function DescriptionList({
  items,
  variant = "stacked",
  columns = 3,
  title,
  titleAction,
  loading = false,
  density = "comfortable",
  onGrey = false,
  note,
  className,
}: {
  items: DescItem[];
  variant?: "stacked" | "inline" | "summary";
  columns?: 2 | 3 | 4;
  title?: string;
  titleAction?: React.ReactNode;
  loading?: boolean;
  density?: "comfortable" | "compact";
  onGrey?: boolean;
  /** Caption under the list, e.g. "Viewing medical details is logged." */
  note?: React.ReactNode;
  className?: string;
}) {
  const label = cn("text-[13px] leading-[18px]", onGrey ? "text-[var(--color-fg-secondary-strong)]" : "text-[var(--color-fg-secondary)]");
  const value = cn("text-foreground", density === "compact" ? "text-sm" : "text-[15px] leading-[22px]");
  const skeleton = <span className="block h-4 w-28 animate-pulse rounded-sm bg-[var(--color-bg-surface-subtle)]" aria-hidden />;
  const cols = { 2: "sm:grid-cols-2", 3: "sm:grid-cols-2 lg:grid-cols-3", 4: "sm:grid-cols-2 lg:grid-cols-4" }[columns];
  const span = { 1: "", 2: "sm:col-span-2", 3: "sm:col-span-2 lg:col-span-3", 4: "sm:col-span-2 lg:col-span-4" };

  return (
    <section className={cn("space-y-3", className)} aria-busy={loading || undefined}>
      {title ? (
        <div className="flex items-center justify-between gap-2">
          <h3 className="text-base font-semibold">{title}</h3>
          {titleAction}
        </div>
      ) : null}
      {variant === "stacked" ? (
        <dl className={cn("grid grid-cols-1 gap-x-6", density === "compact" ? "gap-y-3" : "gap-y-5", cols)}>
          {items.map((it) => (
            <div key={it.label} className={cn("min-w-0 space-y-1", it.span && span[it.span])}>
              <dt className={label}>{it.label}</dt>
              <dd className={cn(value, "break-words")}>{loading ? skeleton : <Value item={it} />}</dd>
            </div>
          ))}
        </dl>
      ) : (
        <dl className="divide-y divide-[var(--color-border-subtle)]">
          {items.map((it, i) => {
            const total = variant === "summary" && i === items.length - 1;
            return (
              <div
                key={it.label}
                className={cn(
                  "grid grid-cols-[minmax(0,1fr)_minmax(0,2fr)] items-baseline gap-4",
                  density === "compact" ? "py-2" : "py-3",
                  total && "border-t border-t-[var(--color-border-panel)] !border-t-2",
                )}
              >
                <dt className={cn(label, total && "font-semibold text-foreground")}>{it.label}</dt>
                <dd className={cn(value, "flex items-baseline gap-2 break-words", variant === "summary" && "justify-end text-right tabular-nums", total && "text-base font-semibold")}>
                  {loading ? skeleton : <Value item={it} />}
                  {it.action ? <span className="ml-auto shrink-0 text-sm">{it.action}</span> : null}
                </dd>
              </div>
            );
          })}
        </dl>
      )}
      {note ? <p className="text-xs text-muted-foreground">{note}</p> : null}
    </section>
  );
}
