import type { ClaimDetail, ClaimDetailAddress } from "@/types";
import { useDrillStack } from "@/components/drill/DrillStackProvider";
import { PeekModal } from "@/components/drill/PeekModal";
import { PayerPeekContent } from "@/components/drill/PayerPeekContent";

type PartiesGridProps = {
  parties: ClaimDetail["parties"];
};

type AddressLike = ClaimDetail["parties"]["billingProvider"]["address"];

/**
 * Address can come back as `ClaimDetailAddress` (line1/line2/city/...) or
 * `{}` (the backend's `Record<string, never>` shape for "missing"). The
 * latter is structurally a regular object with no keys, so a single
 * `Object.keys(addr).length === 0` check is the safe way to detect it
 * without resorting to `'line1' in addr`.
 */
function isEmptyAddress(addr: AddressLike | null | undefined): boolean {
  if (addr === null || addr === undefined) return true;
  return Object.keys(addr).length === 0;
}

function AddressBlock({ address }: { address: AddressLike }) {
  if (isEmptyAddress(address)) return null;
  // After the empty check the cast is safe — the remaining union arm is
  // `ClaimDetailAddress` which has all the fields we read.
  const a = address as ClaimDetailAddress;
  return (
    <div
      className="mt-1 border-t border-dashed border-border/60 pt-2 text-xs leading-relaxed text-muted-foreground"
      data-testid="party-address"
    >
      <div>{a.line1}</div>
      {a.line2 ? <div>{a.line2}</div> : null}
      <div>
        {a.city}, {a.state} {a.zip}
      </div>
    </div>
  );
}

/**
 * Single party card: eyebrow label, name, identity mono line(s), and
 * an optional address block. The card is just a light surface with a
 * border — no shadow, no hover; the drawer is read-only detail content.
 */
function PartyCard({
  testId,
  label,
  name,
  identity,
  address,
  onNameClick,
}: {
  testId: string;
  label: string;
  name: string;
  identity: React.ReactNode;
  address?: AddressLike;
  onNameClick?: () => void;
}) {
  return (
    <div
      data-testid={testId}
      className="flex flex-col gap-2 rounded-lg border border-border/60 bg-muted/30 px-4 py-3 transition-colors hover:border-border hover:bg-muted/40"
    >
      <span className="eyebrow text-muted-foreground">
        {label}
      </span>
      {onNameClick ? (
        <button
          type="button"
          onClick={onNameClick}
          data-testid={`${testId}-name-drill`}
          aria-label={`Drill into ${label.toLowerCase()} ${name}`}
          className="display text-lg text-foreground text-left cursor-pointer drillable rounded-sm px-0 -mx-0"
        >
          {name}
        </button>
      ) : (
        <div className="display text-lg text-foreground">
          {name}
        </div>
      )}
      <div
        className="mono text-[12.5px] text-muted-foreground tabular-nums"
      >
        {identity}
      </div>
      {address ? <AddressBlock address={address} /> : null}
    </div>
  );
}

/**
 * Parties section of the claim detail drawer (SP4).
 *
 * Three stacked cards on mobile (`grid-cols-1`), 3-up grid on desktop
 * (`md:grid-cols-3`). Billing provider carries the full identity + tax
 * id + address; subscriber shows the member record; payer is the slim
 * name+id card. All optional fields (subscriber DOB, line2) are
 * conditionally rendered so a missing value doesn't become "null" in
 * the rendered text.
 */
export function PartiesGrid({ parties }: PartiesGridProps) {
  const { billingProvider, subscriber, payer } = parties;
  // SP21 Phase 5 Task 5.8: payer name opens a PeekModal on top of
  // the drawer — the peek stack (DrillStackProvider) holds at most
  // one peek at a time, so opening payer-peek replaces any earlier
  // peek. The X12 payer id (`payer.id`) is what the peek endpoint
  // expects, NOT the human name.
  const { stack, openPeek, closeTop } = useDrillStack();
  const topPeek = stack[stack.length - 1];

  return (
    <section
      className="flex flex-col gap-3 px-6 py-4"
      data-testid="parties-grid"
    >
      <h3
        data-testid="section-label"
        className="eyebrow text-muted-foreground"
      >
        Parties
      </h3>

      <div
        data-testid="parties-grid-inner"
        className="grid grid-cols-1 md:grid-cols-3 gap-4"
      >
        <PartyCard
          testId="party-billing-provider"
          label="Billing provider"
          name={billingProvider.name}
          identity={
            <>
              <div>NPI {billingProvider.npi}</div>
              {billingProvider.taxId ? (
                <div>Tax ID {billingProvider.taxId}</div>
              ) : null}
            </>
          }
          address={billingProvider.address}
        />

        <PartyCard
          testId="party-subscriber"
          label="Subscriber"
          name={`${subscriber.firstName} ${subscriber.lastName}`}
          identity={
            <>
              <div>Member ID {subscriber.memberId}</div>
              {subscriber.gender ? <div>Gender {subscriber.gender}</div> : null}
              {subscriber.dob ? <div>DOB {subscriber.dob}</div> : null}
            </>
          }
        />

        <PartyCard
          testId="party-payer"
          label="Payer"
          name={payer.name}
          identity={
            <>
              <div>ID {payer.id}</div>
            </>
          }
          // SP21 Phase 5 Task 5.8: payer name is drillable. Clicking
          // pushes a payer peek onto the drill stack; the PeekModal
          // at the bottom of this section renders when the top of
          // the stack is "payer". The payer id used here is the X12
          // payer_id (e.g. "SKCO0") — verified in ClaimDetailPayer
          // type — which is what usePayerSummary expects.
          onNameClick={() => openPeek({ kind: "payer", payerId: payer.id })}
        />
      </div>

      {/* SP21 Phase 5 Task 5.8: payer peek. Mounted at the bottom
          of PartiesGrid so the peek sits on top of the drawer (Radix
          Dialog portals). Closing the peek pops the stack. Only one
          peek renders at a time (the stack caps at 1) — when the
          user opens a payer peek, any earlier peek is replaced. */}
      {topPeek?.kind === "payer" ? (
        <PeekModal
          open
          onClose={closeTop}
          eyebrow="Payer"
          title={payer.name}
        >
          <PayerPeekContent payerId={topPeek.payerId} />
        </PeekModal>
      ) : null}
    </section>
  );
}
