"use client"

import { errorMessageOr } from "@/lib/toast-api-error";

import * as React from "react"

import { useRenderEffect } from "@/hooks/use-changed";
import { ArrowLeft, Layers3, Loader2, X } from "lucide-react"

import { Button } from "@/components/ui/button"
import {
  Sheet,
  SheetContent,
  SheetDescription,
  SheetTitle,
} from "@/components/ui/sheet"
import { cn } from "@/lib/utils"

import { EM_DASH, formatAccounting, formatPrice } from "@/lib/format/numbers"
import { ReportLifecycleBadge } from "@/app/customer/[tenant]/reports/_shared/components/report-lifecycle-badge"
import {
  SortableTh,
  StickyTableScroll,
  useTableSort,
} from "@/app/customer/[tenant]/reports/_shared/components/sortable-table"
import {
  NON_MARKET_PRICE_NOTE,
  bankPricingSummary,
  formatPriceDate,
  fxUsed,
  masterValueIfChanged,
  missingReason,
  priceUsed,
} from "../_lib/pib-bank-pricing"
import { fetchPibPivotDetailClient } from "../_lib/pib-pivot-detail-api"
import type {
  PibBankPricing,
  PibPivotDetailLine,
  PibPivotDetailLot,
  PibPivotDetailPayload,
} from "../_lib/pib-pivot-detail-types"
import type { PibPivotBucketKey } from "../_lib/pib-pivot-data"

/** Accounting-style value with an em dash for absent figures. */
function formatPibValue(value: number | null | undefined): string {
  return formatAccounting(value, EM_DASH)
}

export type PibPivotDetailTarget = {
  bucket: PibPivotBucketKey
  bucketLabel: string
  customerId: number
  bank: string
  client: string
  cellValue: number
}



function InfoChip({
  label,
  value,
  detail,
  mono,
}: {
  label: string
  value: string
  detail?: string
  mono?: boolean
}) {
  return (
    <div className="min-w-0 rounded-xl border border-border/60 bg-card/80 px-3 py-2 shadow-sm backdrop-blur-sm">
      <p className="text-[10px] font-medium uppercase tracking-wider text-muted-foreground">{label}</p>
      <p
        className={cn(
          "mt-0.5 truncate text-sm font-medium text-foreground",
          mono && "font-mono tracking-tight"
        )}
        title={value}
      >
        {value}
      </p>
      {detail ? (
        <p className="mt-0.5 truncate text-xs text-muted-foreground" title={detail}>
          {detail}
        </p>
      ) : null}
    </div>
  )
}

function UnmappedBadge() {
  return (
    <span className="inline-flex w-fit rounded-md bg-amber-100 px-1.5 py-0.5 text-[10px] font-medium text-amber-800 dark:bg-amber-950 dark:text-amber-300">
      Unmapped
    </span>
  )
}

function LabelCodeCell({
  label,
  code,
  unmapped,
  codeMono = true,
}: {
  label: string
  code: string
  unmapped?: boolean
  /** When false, secondary line is a plain name (e.g. asset class) not a short code. */
  codeMono?: boolean
}) {
  const name = label.trim()
  const shortCode = code.trim()

  if (!name && !shortCode) {
    return unmapped ? <UnmappedBadge /> : <span className="text-muted-foreground">—</span>
  }

  return (
    <div className="flex min-w-[8rem] flex-col gap-1 leading-tight">
      {unmapped ? <UnmappedBadge /> : null}
      {!name ? (
        <span
          className={cn(
            "text-[10px] text-muted-foreground",
            codeMono ? "font-mono" : "text-xs"
          )}
        >
          {shortCode}
        </span>
      ) : (
        <>
          <span className="text-xs">{name}</span>
          {shortCode ? (
            <span
              className={cn(
                "text-[10px] text-muted-foreground",
                codeMono ? "font-mono" : "text-xs"
              )}
            >
              {shortCode}
            </span>
          ) : null}
        </>
      )}
    </div>
  )
}

function lotsFor(line: PibPivotDetailLine): PibPivotDetailLot[] {
  return line.transactions?.length ? line.transactions : [line]
}

const formatMarketPrice = (value: number) =>
  formatPrice(value, { minimumFractionDigits: 2, maximumFractionDigits: 4 })
const formatFxRate = (value: number) =>
  formatPrice(value, { minimumFractionDigits: 4, maximumFractionDigits: 6 })

/** Figure (or short label) with an optional small detail line under it. */
function Figure({
  main,
  detail,
  title,
  missing,
}: {
  main: React.ReactNode
  detail?: React.ReactNode
  title?: string
  missing?: boolean
}) {
  return (
    <div className="flex flex-col items-end leading-tight" title={title}>
      <span className={cn("tabular-nums", missing && "font-medium text-amber-700 dark:text-amber-400")}>{main}</span>
      {detail ? <span className="text-[10px] text-muted-foreground">{detail}</span> : null}
    </div>
  )
}

/** The bank price the value used (dated), or why there is none. Never the master price. */
function PriceUsedCell({ pricing }: { pricing: PibBankPricing | null | undefined }) {
  const used = priceUsed(pricing)
  if (used.kind === "bank") {
    return <Figure main={formatMarketPrice(used.value)} detail={formatPriceDate(used.date)} title="Price sent by the bank" />
  }
  if (used.kind === "missing") {
    return <Figure missing main="No bank price" title="The bank sent no price for this ISIN — not counted" />
  }
  const { label, note } = NON_MARKET_PRICE_NOTE[used.kind]
  return <Figure main={<span className="text-muted-foreground">{label}</span>} title={note} />
}

/** The bank FX rate the value used (pair + date), or why there is none. Never the master rate. */
function FxUsedCell({ pricing }: { pricing: PibBankPricing | null | undefined }) {
  const used = fxUsed(pricing)
  if (used.kind === "same") {
    return <Figure main={<span className="text-muted-foreground">—</span>} title={`${used.currency} — no conversion needed`} />
  }
  if (used.kind === "none") {
    return <span className="text-muted-foreground">—</span>
  }
  const pair = `${used.from}→${used.to}`
  if (used.kind === "missing") {
    return <Figure missing main="No bank FX" detail={pair} title={`The bank sent no ${pair} rate — not counted`} />
  }
  const date = formatPriceDate(used.date)
  return (
    <Figure
      main={formatFxRate(used.value)}
      detail={date ? `${pair} · ${date}` : pair}
      title={`1 ${used.from} = ${formatFxRate(used.value)} ${used.to}, sent by the bank`}
    />
  )
}

/** The value, or "Not counted" when the bank sent no price / FX rate for it. */
function BankPricedValue({ lot }: { lot: PibPivotDetailLot }) {
  const reason = missingReason(lot.bankPricing, lot.bankName)
  if (reason) {
    return <Figure missing main="Not counted" title={reason} />
  }
  const master = masterValueIfChanged(lot)
  return (
    <Figure
      main={formatPibValue(lot.value)}
      detail={master != null ? `master ${formatPibValue(master)}` : null}
      title={master != null ? "Master-price value shown for reference only" : undefined}
    />
  )
}

const bankPriceOf = (lot: PibPivotDetailLot) => lot.bankPricing?.bankPrice ?? -Infinity
const bankFxOf = (lot: PibPivotDetailLot) => lot.bankPricing?.bankFx ?? -Infinity

const HOLDINGS_SORT_ACCESSORS = {
  isin: (line: PibPivotDetailLine) => line.isin,
  name: (line: PibPivotDetailLine) => line.name || line.assetType,
  macro: (line: PibPivotDetailLine) => line.macro,
  assetType: (line: PibPivotDetailLine) => line.assetType,
  pibClass: (line: PibPivotDetailLine) => line.pibClassLabel,
  marketPrice: bankPriceOf,
  fxRate: bankFxOf,
  value: (line: PibPivotDetailLine) => line.value,
}

const LOT_SORT_ACCESSORS = {
  refId: (lot: PibPivotDetailLot) => lot.refId,
  bankName: (lot: PibPivotDetailLot) => lot.bankName,
  tradeDate: (lot: PibPivotDetailLot) => lot.tradeDate,
  quantity: (lot: PibPivotDetailLot) => lot.quantity,
  currency: (lot: PibPivotDetailLot) => lot.currency,
  price: (lot: PibPivotDetailLot) => lot.price,
  purchaseValue: (lot: PibPivotDetailLot) => lot.purchaseValue,
  marketPrice: bankPriceOf,
  fxRate: bankFxOf,
  value: (lot: PibPivotDetailLot) => lot.value,
}

function HoldingsTable({
  detail,
  trackPibUnmapped = true,
  onIsinClick,
}: {
  detail: PibPivotDetailPayload
  trackPibUnmapped?: boolean
  onIsinClick: (line: PibPivotDetailLine) => void
}) {
  const { rows: sortedLines, toggle, directionFor } = useTableSort(detail.lines, HOLDINGS_SORT_ACCESSORS)
  // Bank prices on: Macro / Asset type fold into the Name cell so Price / FX fit without a sideways scroll.
  const showBankPricing = detail.priceSource === "bank"

  return (
    <StickyTableScroll className="max-h-[max(20rem,calc(100dvh-24rem))]">
      <table className={cn("w-full border-collapse text-sm", showBankPricing ? "min-w-[760px]" : "min-w-[820px]")}>
        <thead>
          <tr>
            <SortableTh label="ISIN" direction={directionFor("isin")} onSort={() => toggle("isin")} />
            <SortableTh
              label="Name"
              className={showBankPricing ? "min-w-[14rem]" : "min-w-[18rem]"}
              direction={directionFor("name")}
              onSort={() => toggle("name")}
            />
            {showBankPricing ? null : (
              <>
                <SortableTh label="Macro" className="min-w-[8rem]" direction={directionFor("macro")} onSort={() => toggle("macro")} />
                <SortableTh label="Asset type" className="min-w-[10rem]" direction={directionFor("assetType")} onSort={() => toggle("assetType")} />
              </>
            )}
            <SortableTh label="PIB class" className="min-w-[11rem]" direction={directionFor("pibClass")} onSort={() => toggle("pibClass")} />
            {showBankPricing ? (
              <>
                <SortableTh label="Bank price" align="right" direction={directionFor("marketPrice")} onSort={() => toggle("marketPrice")} />
                <SortableTh label="Bank FX" align="right" direction={directionFor("fxRate")} onSort={() => toggle("fxRate")} />
              </>
            ) : null}
            <SortableTh label="Value" align="right" direction={directionFor("value")} onSort={() => toggle("value")} />
          </tr>
        </thead>
        <tbody>
          {sortedLines.map((line, index) => {
            const isPotential = Boolean(line.isPotential)
            const isUnmapped =
              !isPotential &&
              (!line.isAcMapped || (trackPibUnmapped && !line.isPibAssigned))
            const lotCount = lotsFor(line).length
            const isinTitle =
              lotCount > 1 ? `View ${lotCount} transactions` : "View transaction"
            const isinLabel = line.isin || "—"
            const macroLine = [line.macro, line.assetType].filter((part) => part.trim() !== "").join(" · ")

            return (
            <tr
              key={`${line.isin}-${line.assetType}-${index}`}
              className={cn(
                "border-t border-border/60",
                index % 2 === 1 && "bg-muted/20",
                isUnmapped && "bg-amber-50/80 dark:bg-amber-950/20",
                isPotential && "bg-amber-500/5 dark:bg-amber-500/10"
              )}
            >
              <td className="px-3 py-2 font-mono text-xs">
                <button
                  type="button"
                  className="text-left underline-offset-2 hover:text-primary hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
                  title={isinTitle}
                  onClick={() => onIsinClick(line)}
                >
                  {isinLabel}
                </button>
              </td>
              <td className="max-w-[28rem] px-3 py-2" title={line.name || line.assetType}>
                <div className="flex flex-col gap-1">
                  {isPotential ? (
                    <ReportLifecycleBadge
                      kind="potential"
                      title="On Structured Products Potential tab — shown here but not included in PIB totals"
                      className="w-fit"
                    />
                  ) : null}
                  <span className="line-clamp-2">{line.name || line.assetType || "—"}</span>
                  {showBankPricing && macroLine ? (
                    <span className="text-[11px] text-muted-foreground">
                      {macroLine}
                      {!line.isAcMapped ? <span className="ml-1.5"><UnmappedBadge /></span> : null}
                    </span>
                  ) : null}
                </div>
              </td>
              {showBankPricing ? null : (
                <>
                  <td className="px-3 py-2 align-top">
                    <LabelCodeCell
                      label={line.macro}
                      code={line.assetClassLabel || line.assetClass}
                      codeMono={false}
                      unmapped={!line.isAcMapped}
                    />
                  </td>
                  <td className="max-w-[14rem] px-3 py-2 text-xs" title={line.assetType}>
                    <span className="line-clamp-2">{line.assetType || "—"}</span>
                  </td>
                </>
              )}
              <td className="px-3 py-2 align-top">
                <LabelCodeCell
                  label={line.pibClassLabel}
                  code={line.pibClass}
                  unmapped={trackPibUnmapped && !line.isPibAssigned}
                />
              </td>
              {showBankPricing ? (
                <>
                  <td className="px-3 py-2 text-right text-xs">
                    <PriceUsedCell pricing={line.bankPricing} />
                  </td>
                  <td className="px-3 py-2 text-right text-xs">
                    <FxUsedCell pricing={line.bankPricing} />
                  </td>
                </>
              ) : null}
              <td
                className={cn(
                  "px-3 py-2 text-right tabular-nums",
                  line.value < 0 && "text-red-600 dark:text-red-400"
                )}
              >
                {showBankPricing ? <BankPricedValue lot={line} /> : formatPibValue(line.value)}
              </td>
            </tr>
            )
          })}
        </tbody>
      </table>
    </StickyTableScroll>
  )
}

function TransactionTable({
  line,
  reportingCurrency,
  showBankPricing = false,
}: {
  line: PibPivotDetailLine
  reportingCurrency: string
  showBankPricing?: boolean
}) {
  const lots = React.useMemo(() => lotsFor(line), [line])
  const { rows: sortedLots, toggle, directionFor } = useTableSort(lots, LOT_SORT_ACCESSORS)
  const totalValue = lots.reduce((sum, lot) => sum + (Number.isFinite(lot.value) ? lot.value : 0), 0)
  const totalQty = lots.reduce((sum, lot) => sum + (Number.isFinite(lot.quantity) ? lot.quantity : 0), 0)
  // Bank prices on: the bank is the cell's own and the currency shows in the FX pair, so those
  // two columns make way for Bank price / Bank FX.
  const showBankAndCurrency = !showBankPricing

  return (
    <div className="space-y-2">
      <p className="text-sm font-medium">
        {line.name || line.isin || "Transactions"}
        {line.isin ? (
          <span className="ml-2 font-mono text-xs font-normal text-muted-foreground">
            {line.isin}
          </span>
        ) : null}
      </p>
      <StickyTableScroll className="max-h-[max(16rem,calc(100dvh-24rem))]">
        <table className={cn("w-full border-collapse text-sm", showBankPricing ? "min-w-[820px]" : "min-w-[880px]")}>
          <thead>
            <tr>
              <SortableTh label="Ref ID" direction={directionFor("refId")} onSort={() => toggle("refId")} />
              {showBankAndCurrency ? (
                <SortableTh label="Bank Name" direction={directionFor("bankName")} onSort={() => toggle("bankName")} />
              ) : null}
              <SortableTh label="Trade Date" direction={directionFor("tradeDate")} onSort={() => toggle("tradeDate")} />
              <SortableTh label="Quantity" align="right" direction={directionFor("quantity")} onSort={() => toggle("quantity")} />
              {showBankAndCurrency ? (
                <SortableTh label="Currency" direction={directionFor("currency")} onSort={() => toggle("currency")} />
              ) : null}
              <SortableTh label="Price" align="right" direction={directionFor("price")} onSort={() => toggle("price")} />
              <SortableTh label="Purchase Value" align="right" direction={directionFor("purchaseValue")} onSort={() => toggle("purchaseValue")} />
              {showBankPricing ? (
                <>
                  <SortableTh label="Bank price" align="right" direction={directionFor("marketPrice")} onSort={() => toggle("marketPrice")} />
                  <SortableTh label="Bank FX" align="right" direction={directionFor("fxRate")} onSort={() => toggle("fxRate")} />
                </>
              ) : null}
              <SortableTh label="Market Value" align="right" direction={directionFor("value")} onSort={() => toggle("value")} />
            </tr>
          </thead>
          <tbody>
            {sortedLots.map((lot, index) => (
              <tr
                key={`${lot.refId}-${index}`}
                className={cn(
                  "border-t border-border/60",
                  index % 2 === 1 && "bg-muted/20"
                )}
              >
                <td className="px-3 py-2">{lot.refId || "—"}</td>
                {showBankAndCurrency ? <td className="px-3 py-2">{lot.bankName || "—"}</td> : null}
                <td className="px-3 py-2">{lot.tradeDate || "—"}</td>
                <td className="px-3 py-2 text-right tabular-nums">
                  {formatPibValue(lot.quantity)}
                </td>
                {showBankAndCurrency ? <td className="px-3 py-2">{lot.currency || reportingCurrency}</td> : null}
                <td className="px-3 py-2 text-right tabular-nums">
                  {formatPibValue(lot.price)}
                </td>
                <td className="px-3 py-2 text-right tabular-nums">
                  {formatPibValue(lot.purchaseValue)}
                </td>
                {showBankPricing ? (
                  <>
                    <td className="px-3 py-2 text-right text-xs">
                      <PriceUsedCell pricing={lot.bankPricing} />
                    </td>
                    <td className="px-3 py-2 text-right text-xs">
                      <FxUsedCell pricing={lot.bankPricing} />
                    </td>
                  </>
                ) : null}
                <td
                  className={cn(
                    "px-3 py-2 text-right tabular-nums",
                    lot.value < 0 && "text-red-600 dark:text-red-400"
                  )}
                >
                  {showBankPricing ? <BankPricedValue lot={lot} /> : formatPibValue(lot.value)}
                </td>
              </tr>
            ))}
            <tr className="border-t border-border bg-muted/50 font-semibold">
              <td className="px-3 py-2.5 text-right" colSpan={showBankAndCurrency ? 3 : 2}>
                Total
              </td>
              <td className="px-3 py-2.5 text-right tabular-nums">
                {formatPibValue(totalQty)}
              </td>
              <td className="px-3 py-2.5" colSpan={showBankPricing ? 4 : 3} />
              <td className="px-3 py-2.5 text-right tabular-nums">
                {formatPibValue(totalValue)}
              </td>
            </tr>
          </tbody>
        </table>
      </StickyTableScroll>
    </div>
  )
}

/** Bank prices on: one strip with how the cell was valued, replacing three cards and a legend. */
function BankPricingStrip({
  bank,
  valued,
  missing,
  masterTotal,
  currency,
}: {
  bank: string
  valued: number
  missing: number
  masterTotal: number
  currency: string
}) {
  const bankLabel = bank.trim() || "the bank"
  return (
    <div className="flex flex-col gap-1 rounded-xl border border-border/60 bg-card px-3 py-2 text-xs shadow-sm">
      <div className="flex flex-wrap items-center gap-x-4 gap-y-1">
        <span className="font-medium text-foreground">Bank prices · {bankLabel}</span>
        <span>
          <span className="font-medium tabular-nums">{valued}</span> of {valued + missing} holdings valued
        </span>
        {missing > 0 ? (
          <span className="font-medium text-amber-700 dark:text-amber-400">{missing} not counted</span>
        ) : null}
        <span className="text-muted-foreground" title="Same holdings at master prices — reference only, not used">
          Master reference {currency} {formatPibValue(masterTotal)}
        </span>
      </div>
      <p className="text-muted-foreground">
        Value = quantity × bank price × bank FX. No master fallback: a holding {bankLabel} sent no price or FX rate
        for is not counted. Cash is fixed at 1.00; a holding already in {currency} uses the bank&apos;s {currency}→{currency} rate.
      </p>
    </div>
  )
}

export function PibPivotDetailDialog({
  target,
  asOfDate = "",
  bankPrices = false,
  open,
  onOpenChange,
}: {
  target: PibPivotDetailTarget | null
  asOfDate?: string
  /** Same "Bank prices" toggle as the pivot, so the holdings add up to the clicked cell. */
  bankPrices?: boolean
  open: boolean
  onOpenChange: (open: boolean) => void
}) {
  const [detail, setDetail] = React.useState<PibPivotDetailPayload | null>(null)
  const [selectedLine, setSelectedLine] = React.useState<PibPivotDetailLine | null>(null)
  const [loading, setLoading] = React.useState(false)
  const [errorMessage, setErrorMessage] = React.useState<string | null>(null)

  // Opening, closing or retargeting starts from a clean slate (adjusted during render, not in an effect).
  useRenderEffect([open, target, asOfDate, bankPrices], () => {
    setDetail(null)
    setErrorMessage(null)
    setSelectedLine(null)
    setLoading(Boolean(open && target))
  })

  React.useEffect(() => {
    if (!open || !target) return

    const controller = new AbortController()

    fetchPibPivotDetailClient(
      {
        bucket: target.bucket,
        customerId: target.customerId,
        bank: target.bank,
        asOfDate: asOfDate.trim() || undefined,
        bankPrices,
      },
      controller.signal
    )
      .then((payload) => {
        setDetail(payload)
      })
      .catch((error: unknown) => {
        if (controller.signal.aborted) return
        setErrorMessage(errorMessageOr(error, "Could not load holdings."))
      })
      .finally(() => {
        if (!controller.signal.aborted) {
          setLoading(false)
        }
      })

    return () => controller.abort()
  }, [open, target, asOfDate, bankPrices])

  const currency = detail?.defaultCurrencyCode ?? "USD"
  const bankSummary = detail?.priceSource === "bank" ? bankPricingSummary(detail.lines) : null
  const trackPibUnmapped = target?.bucket !== "moneyMarket"

  return (
    <Sheet open={open} onOpenChange={onOpenChange}>
      <SheetContent
        side="right"
        showCloseButton={false}
        className={cn(
          "flex h-dvh w-full flex-col gap-0 overflow-hidden bg-muted/30 p-0",
          "data-[side=right]:w-full data-[side=right]:sm:max-w-none",
          "data-[side=right]:sm:!w-[min(72rem,calc(100vw-1.5rem))]"
        )}
      >
        <div className="shrink-0 space-y-2 border-b border-border/60 bg-card/80 px-4 pt-4 pb-3 backdrop-blur-md">
          <p className="text-[10px] font-semibold uppercase tracking-widest text-muted-foreground">
            {selectedLine ? "Transactions" : "Holdings"}
          </p>
          <div className="flex items-center justify-between gap-2">
            <SheetTitle className="flex min-w-0 items-center gap-2 text-left text-base font-semibold tracking-tight">
              {selectedLine ? (
                <Button
                  type="button"
                  variant="ghost"
                  size="icon-sm"
                  className="rounded-lg"
                  onClick={() => setSelectedLine(null)}
                  aria-label="Back to holdings"
                >
                  <ArrowLeft className="size-4" />
                </Button>
              ) : (
                <span className="flex size-8 shrink-0 items-center justify-center rounded-xl bg-primary text-primary-foreground shadow-md shadow-primary/25">
                  <Layers3 className="size-3.5" />
                </span>
              )}
              <span className="truncate">
                {selectedLine
                  ? selectedLine.name || selectedLine.isin || "Transactions"
                  : (target?.bucketLabel ?? "PIB bucket holdings")}
              </span>
            </SheetTitle>
            <Button
              type="button"
              variant="ghost"
              size="icon-sm"
              className="rounded-lg"
              onClick={() => onOpenChange(false)}
              aria-label="Close"
            >
              <X className="size-4" />
            </Button>
          </div>
          <SheetDescription className="sr-only">
            Clubbed holdings for this PIB pivot cell, with lot-level transactions on amount click.
          </SheetDescription>
        </div>

        <div className="flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto px-4 py-4">
          {target ? (
            <section className="flex flex-col gap-3 rounded-2xl border border-border/60 bg-card p-3 shadow-sm">
              <div className="grid gap-2 sm:grid-cols-3">
                <InfoChip label="Customer" value={target.client || "—"} />
                <InfoChip label="Bank" value={target.bank || "—"} />
                <InfoChip label="PIB bucket" value={target.bucketLabel || "—"} />
              </div>
              {detail ? (
                <>
                  <div className="grid gap-2 sm:grid-cols-3">
                    <InfoChip label="Holdings" value={String(detail.lineCount)} />
                    <InfoChip
                      label={`Bucket total (${currency})`}
                      value={formatPibValue(detail.totalValue)}
                    />
                    <InfoChip label="Pivot cell" value={formatPibValue(target.cellValue)} />
                  </div>
                  {bankSummary ? (
                    <BankPricingStrip
                      bank={target.bank}
                      valued={bankSummary.valued}
                      missing={bankSummary.missing}
                      masterTotal={bankSummary.masterTotal}
                      currency={currency}
                    />
                  ) : null}
                  {trackPibUnmapped ? (
                    <div className="grid gap-2 sm:grid-cols-3">
                      <InfoChip
                        label={`Assigned (${currency})`}
                        value={formatPibValue(detail.assignedValue)}
                        detail="OS / ISIN master PIB"
                      />
                      <InfoChip
                        label={`Inferred (${currency})`}
                        value={formatPibValue(detail.inferredValue)}
                        detail={
                          detail.unmappedPibCount > 0
                            ? `${detail.unmappedPibCount} holding${detail.unmappedPibCount === 1 ? "" : "s"} · AC rules only`
                            : "None in this cell"
                        }
                      />
                      {detail.unmappedAcCount > 0 ? (
                        <InfoChip
                          label="Unmapped Macro"
                          value={String(detail.unmappedAcCount)}
                          detail="No Macro Asset Class for holding"
                        />
                      ) : (
                        <div className="hidden sm:block" />
                      )}
                    </div>
                  ) : detail.unmappedAcCount > 0 ? (
                    <InfoChip
                      label="Unmapped Macro"
                      value={String(detail.unmappedAcCount)}
                      detail="No Macro Asset Class for holding"
                    />
                  ) : null}
                  {detail.potentialCount > 0 ? (
                    <InfoChip
                      label={`Potential (${currency})`}
                      value={formatPibValue(detail.potentialValue)}
                      detail={`${detail.potentialCount} note${detail.potentialCount === 1 ? "" : "s"} · shown, not in PIB totals`}
                    />
                  ) : null}
                </>
              ) : null}
            </section>
          ) : null}

          {loading ? (
            <div className="flex items-center gap-2 py-10 text-sm text-muted-foreground">
              <Loader2 className="size-4 animate-spin" />
              Loading…
            </div>
          ) : null}

          {errorMessage ? <p className="text-destructive text-sm">{errorMessage}</p> : null}

          {!loading && !errorMessage && detail ? (
            detail.lines.length === 0 ? (
              <p className="text-muted-foreground text-sm">No holdings in this bucket.</p>
            ) : (
              <>
                {selectedLine ? (
                  <TransactionTable
                    line={selectedLine}
                    reportingCurrency={currency}
                    showBankPricing={detail.priceSource === "bank"}
                  />
                ) : (
                  <HoldingsTable
                    detail={detail}
                    trackPibUnmapped={trackPibUnmapped}
                    onIsinClick={setSelectedLine}
                  />
                )}
              </>
            )
          ) : null}
        </div>
      </SheetContent>
    </Sheet>
  )
}
