import { useState } from "react";
import { ChevronDown, ChevronRight } from "lucide-react";
import { fmt } from "@/lib/format";
import { cn } from "@/lib/utils";
import type { RemitDetail } from "@/hooks/useRemitDetail";
import type {
  RemittanceClaimLevelAdjustment,
  ServiceLinePayment,
} from "@/types";

/**
 * One row of CAS adjustments attached to a single SLP. The parent
 * builds these by looking up CAS rows in the line-reconciliation
 * endpoint's per-line `adjustments` arrays. We model the row as a
 * flat tuple of `(slp, adjustments)` so the panel can sort by
 * line number without a join.
 */
export type PerLineCasGroup = {
  slp: ServiceLinePayment;
  adjustments: Array<{
    groupCode: string;
    reasonCode: string;
    amount: string;
  }>;
};

type CasAdjustmentsPanelProps = {
  adjustments: NonNullable<RemitDetail["adjustments"]>;
  /**
   * SP7: optional per-line SVC breakdown. When provided, the panel
   * renders a "Per-line" section above the aggregate rollup and a
   * "Claim-level" section below it.
   */
  perLine?: PerLineCasGroup[];
  claimLevelAdjustments?: RemittanceClaimLevelAdjustment[];
};

/**
 * Group adjustments by `(group, reason)` so a single CARC that fires
 * multiple times in the same remit (common — e.g. CO-45 hitting each
 * service line of a multi-line claim) collapses into one row with a
 * `count` and a cumulative `total`. Sorted by absolute dollar impact
 * so the eye lands on the biggest hit first.
 */
type CasGroup = {
  group: string;
  reason: string;
  label: string;
  total: number;
  count: number;
};

function groupAdjustments(
  adjustments: NonNullable<RemitDetail["adjustments"]>
): CasGroup[] {
  const byKey = new Map<string, CasGroup>();
  for (const adj of adjustments) {
    const key = `${adj.group}-${adj.reason}`;
    const existing = byKey.get(key);
    if (existing) {
      existing.total += adj.amount;
      existing.count += 1;
    } else {
      byKey.set(key, {
        group: adj.group,
        reason: adj.reason,
        label: adj.label,
        total: adj.amount,
        count: 1,
      });
    }
  }
  return Array.from(byKey.values()).sort(
    (a, b) => Math.abs(b.total) - Math.abs(a.total)
  );
}

/**
 * Single CAS row. The CARC key is the headline; label is secondary
 * metadata; amount and quantity use the project's mono treatment so
 * columns line up vertically.
 */
function CasRow({ group }: { group: CasGroup }) {
  return (
    <div
      data-testid="cas-row"
      data-carc={`${group.group}-${group.reason}`}
      className="grid grid-cols-[6rem_1fr_5rem_6rem] items-baseline gap-3 px-4 py-2 border-b border-[color:var(--m-border-heavy)]/10 last:border-b-0 transition-colors hover:bg-[color:var(--m-surface)]/50"
    >
      <span
        className="mono text-sm tabular-nums text-[color:var(--m-ink-primary)]"
      >
        {group.group}-{group.reason}
      </span>
      <span className="text-sm text-[color:var(--m-ink-secondary)]">{group.label}</span>
      <span
        className="text-right mono text-sm tabular-nums text-[color:var(--m-ink-tertiary)]"
        data-testid="cas-count"
      >
        ×{group.count}
      </span>
      <span
        className="text-right mono text-base tabular-nums text-[color:var(--m-ink-primary)] font-semibold"
        data-testid="cas-amount"
      >
        {fmt.usdPrecise(group.total)}
      </span>
    </div>
  );
}

/**
 * Collapsible CAS adjustments panel for the remittance detail drawer.
 *
 * Lists every CARC reason code that fired on the remit, grouped by
 * (group, reason) so a single CO-45 hitting N service lines reads as
 * one row with `×N` and a cumulative dollar amount. The label is the
 * backend-supplied CARC dictionary lookup (SP3 P2), so we never have
 * to ship a client-side code table.
 *
 * Default-open when there are ≤ 3 groups (a small handful of codes
 * the user is likely to want to see immediately); collapsed when the
 * list is longer so the drawer doesn't get buried under a wall of
 * CARC rows.
 */
export function CasAdjustmentsPanel({
  adjustments,
  perLine,
  claimLevelAdjustments,
}: CasAdjustmentsPanelProps) {
  const groups = groupAdjustments(adjustments);
  const [open, setOpen] = useState(groups.length <= 3);

  const hasPerLine = (perLine?.length ?? 0) > 0;
  const hasClaimLevel = (claimLevelAdjustments?.length ?? 0) > 0;
  const hasAny =
    groups.length > 0 || hasPerLine || hasClaimLevel;

  if (!hasAny) return null;

  return (
    <section
      className="flex flex-col gap-3 px-6 py-4"
      data-testid="cas-adjustments-panel"
    >
      {hasPerLine ? (
        <PerLineSection perLine={perLine ?? []} />
      ) : null}

      {groups.length > 0 ? (
        <>
          <button
            type="button"
            onClick={() => setOpen((v) => !v)}
            aria-expanded={open}
            aria-controls="cas-adjustments-list"
            className="flex items-center gap-2 text-left group"
            data-testid="cas-toggle"
          >
            {open ? (
              <ChevronDown className="h-3.5 w-3.5 text-[color:var(--m-ink-tertiary)] group-hover:text-[color:var(--m-ink-primary)] transition-colors" aria-hidden />
            ) : (
              <ChevronRight className="h-3.5 w-3.5 text-[color:var(--m-ink-tertiary)] group-hover:text-[color:var(--m-ink-primary)] transition-colors" aria-hidden />
            )}
            <h3
              data-testid="section-label"
              className="eyebrow text-[color:var(--m-ink-tertiary)] group-hover:text-[color:var(--m-ink-primary)] transition-colors"
            >
              CAS Adjustments ({groups.length})
            </h3>
          </button>

          {open ? (
            <div
              id="cas-adjustments-list"
              data-testid="cas-adjustments-list"
              className={cn(
                "flex flex-col rounded-lg border border-[color:var(--m-border-heavy)]/30",
                "bg-[color:var(--m-surface)]/40 overflow-hidden"
              )}
            >
              {/* Header row — labels for the 4-column grid */}
              <div className="grid grid-cols-[6rem_1fr_5rem_6rem] gap-3 px-4 py-2 border-b border-[color:var(--m-border-heavy)]/20 bg-[color:var(--m-surface)]/60">
                <span className="eyebrow text-[color:var(--m-ink-tertiary)]">
                  CARC
                </span>
                <span className="eyebrow text-[color:var(--m-ink-tertiary)]">
                  Reason
                </span>
                <span className="text-right eyebrow text-[color:var(--m-ink-tertiary)]">
                  Hits
                </span>
                <span className="text-right eyebrow text-[color:var(--m-ink-tertiary)]">
                  Amount
                </span>
              </div>
              {groups.map((g) => (
                <CasRow
                  key={`${g.group}-${g.reason}`}
                  group={g}
                />
              ))}
            </div>
          ) : null}
        </>
      ) : null}

      {hasClaimLevel ? (
        <ClaimLevelSection adjustments={claimLevelAdjustments ?? []} />
      ) : null}
    </section>
  );
}

/**
 * SP7: per-line section. One card per SVC composite, showing the
 * procedure code + line number + its CAS rows.
 */
function PerLineSection({ perLine }: { perLine: PerLineCasGroup[] }) {
  return (
    <div
      data-testid="per-line-cas-section"
      className="flex flex-col gap-2"
    >
      <h3
        data-testid="section-label"
        className="eyebrow text-[color:var(--m-ink-tertiary)]"
      >
        Per-line Adjustments ({perLine.length})
      </h3>
      {perLine.map((g) => (
        <PerLineRow key={g.slp.id} group={g} />
      ))}
    </div>
  );
}

function PerLineRow({ group }: { group: PerLineCasGroup }) {
  const total = group.adjustments.reduce(
    (acc, a) => acc + Number(a.amount || 0),
    0,
  );
  return (
    <div
      data-testid="per-line-cas-row"
      data-line-number={group.slp.lineNumber}
      className="flex flex-col gap-1 px-3 py-2 rounded-md border border-[color:var(--m-border-heavy)]/15 bg-[color:var(--m-surface)]/40 transition-colors hover:border-[color:var(--m-border-heavy)]/30"
    >
      <div className="flex items-baseline justify-between font-mono text-sm">
        <span className="text-[color:var(--m-ink-primary)]">
          <span className="font-semibold">{group.slp.procedureCode}</span>
          <span className="text-[color:var(--m-ink-tertiary)] ml-2">
            #{group.slp.lineNumber}
          </span>
        </span>
        <span
          className="tabular-nums text-[color:var(--m-ink-primary)] font-semibold"
          data-testid="per-line-cas-total"
        >
          {fmt.usdPrecise(total)}
        </span>
      </div>
      {group.adjustments.length > 0 ? (
        <ul className="text-xs font-mono text-[color:var(--m-ink-tertiary)] space-y-0.5">
          {group.adjustments.map((a, i) => (
            <li
              key={i}
              data-testid="per-line-cas-entry"
              data-carc={`${a.groupCode}-${a.reasonCode}`}
            >
              <span className="text-[color:var(--m-ink-secondary)]">{a.groupCode}-{a.reasonCode}</span>
              <span className="ml-2 tabular-nums">{fmt.usdPrecise(Number(a.amount))}</span>
            </li>
          ))}
        </ul>
      ) : null}
    </div>
  );
}

/**
 * SP7: claim-level (CLP-level) CAS bucket. Rendered as a flat list
 * under a "Claim-level adjustments" sub-header, below the per-line
 * section and the aggregate rollup.
 */
function ClaimLevelSection({
  adjustments,
}: {
  adjustments: RemittanceClaimLevelAdjustment[];
}) {
  return (
    <div
      data-testid="claim-level-cas-section"
      className="flex flex-col gap-2"
    >
      <h3
        data-testid="section-label"
        className="eyebrow text-[color:var(--m-ink-tertiary)]"
      >
        Claim-level adjustments ({adjustments.length})
      </h3>
      <ul className="text-xs font-mono space-y-0.5">
        {adjustments.map((a) => (
          <li
            key={a.id}
            data-testid="claim-level-cas-entry"
            data-carc={`${a.groupCode}-${a.reasonCode}`}
            className="flex justify-between px-3 py-1.5 rounded-md bg-[color:var(--m-surface)]/40 hover:bg-[color:var(--m-surface)]/70 transition-colors"
          >
            <span className="text-[color:var(--m-ink-primary)]">
              {a.groupCode}-{a.reasonCode}
            </span>
            <span className="tabular-nums text-[color:var(--m-ink-primary)] font-semibold">
              {fmt.usdPrecise(Number(a.amount))}
            </span>
          </li>
        ))}
      </ul>
    </div>
  );
}
