"use client";

import * as React from "react";

import { Layers3, Loader2, X } from "lucide-react";

import { useRenderEffect } from "@/hooks/use-changed";
import { Button } from "@/components/ui/button";
import {
  Sheet,
  SheetContent,
  SheetDescription,
  SheetTitle,
} from "@/components/ui/sheet";
import {
  SortableTh,
  StickyTableScroll,
  useTableSort,
} from "@/app/customer/[tenant]/reports/_shared/components/sortable-table";
import { formatMoneyWithCode, formatQuantity } from "@/lib/format/numbers";
import { REPORT_DEFAULT_CURRENCY } from "@/config/report-defaults";
import { cn } from "@/lib/utils";
import { errorMessageOr } from "@/lib/toast-api-error";

import { fetchAssetAnalyticsPositionsClient } from "../../_lib/asset-analytics-positions-api";
import type {
  AssetAnalyticsPositionRow,
  AssetAnalyticsPositionsData,
  AssetAnalyticsPositionsTotals,
} from "../../_lib/map-asset-analytics-positions";
import { AssetAnalyticsOptionsPanel } from "./asset-analytics-options-panel";
import { ACCUMULATORS_TAB_SLUG, DERIVATIVES_TAB_SLUG, STRUCTURE_TAB_SLUG } from "./schema";
import { ShowExpiredToggle } from "./show-expired-toggle";

export type AssetAnalyticsPositionsTarget = {
  tickerId: string;
  assetClassSlug: string;
  tickerDisplay: string;
  productName: string;
  assetClass: string;
};

type ViewMode = "bank" | "client" | "detail" | "options";

type GroupBy = "bank" | "client";

type BankFigures = {
  positions: number;
  quantity: number;
  purchaseValueUsd: number;
  marketValueUsd: number;
  gainLossUsd: number;
  /** Expired holdings with no close on record by the day they ended (market value unknown). */
  unvalued: number;
};

type SectionStatus = AssetAnalyticsPositionRow["status"];

/** One bank's / client's figures within a single status section. */
type GroupSummaryRow = BankFigures & { name: string };

const SORT_ACCESSORS = {
  refId: (row: AssetAnalyticsPositionRow) => row.refId,
  clientName: (row: AssetAnalyticsPositionRow) => row.clientName,
  bankName: (row: AssetAnalyticsPositionRow) => row.bankName,
  tradeDate: (row: AssetAnalyticsPositionRow) => row.tradeDate,
  quantity: (row: AssetAnalyticsPositionRow) => row.quantity,
  purchaseValue: (row: AssetAnalyticsPositionRow) => row.purchaseValueUsdNum,
  marketValue: (row: AssetAnalyticsPositionRow) => row.marketValueUsdNum,
  gainLoss: (row: AssetAnalyticsPositionRow) => row.gainLoss,
};

const GROUP_SORT_ACCESSORS = {
  name: (row: GroupSummaryRow) => row.name,
  positions: (row: GroupSummaryRow) => row.positions,
  quantity: (row: GroupSummaryRow) => row.quantity,
  purchaseValue: (row: GroupSummaryRow) => row.purchaseValueUsd,
  marketValue: (row: GroupSummaryRow) => row.marketValueUsd,
  gainLoss: (row: GroupSummaryRow) => row.gainLossUsd,
};

const GROUP_KEY: Record<GroupBy, (row: AssetAnalyticsPositionRow) => string> = {
  bank: (row) => row.bankName,
  client: (row) => row.clientName,
};

function segmentClass(active: boolean) {
  return cn(
    "rounded-md px-3 py-1.5 text-xs font-medium transition-colors",
    active
      ? "bg-background text-primary shadow-sm"
      : "text-muted-foreground hover:text-foreground",
  );
}

function nameWithoutLeadingIsin(name: string, isin: string): string {
  const trimmed = name.trim();
  const code = isin.trim();
  if (!trimmed || !code) return trimmed;
  const prefix = new RegExp(`^${code.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s+`, "i");
  return trimmed.replace(prefix, "").trim() || trimmed;
}

function InfoChip({
  label,
  value,
  mono,
}: {
  label: string;
  value: 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="font-medium text-[10px] text-muted-foreground uppercase tracking-wider">
        {label}
      </p>
      <p
        className={cn(
          "mt-0.5 truncate text-foreground text-sm font-medium",
          mono && "font-mono tracking-tight",
        )}
        title={value}
      >
        {value}
      </p>
    </div>
  );
}

function emptyFigures(): BankFigures {
  return { positions: 0, quantity: 0, purchaseValueUsd: 0, marketValueUsd: 0, gainLossUsd: 0, unvalued: 0 };
}

function addToFigures(figures: BankFigures, row: AssetAnalyticsPositionRow) {
  figures.positions += 1;
  figures.quantity += row.quantity;
  figures.purchaseValueUsd += row.purchaseValueUsdNum;
  if (row.marketValueUsdNum === null) figures.unvalued += 1;
  else figures.marketValueUsd += row.marketValueUsdNum;
}

/** Gain/loss from the USD aggregate (row.gainLoss is in each row's own currency and must not be summed). */
function withGain(figures: BankFigures): BankFigures {
  return { ...figures, gainLossUsd: figures.marketValueUsd - figures.purchaseValueUsd };
}

function groupPositions(rows: AssetAnalyticsPositionRow[], groupBy: GroupBy): GroupSummaryRow[] {
  const groups = new Map<string, BankFigures>();
  for (const row of rows) {
    const key = GROUP_KEY[groupBy](row) || "—";
    const figures = groups.get(key) ?? emptyFigures();
    addToFigures(figures, row);
    groups.set(key, figures);
  }
  return Array.from(groups.entries()).map(([name, figures]) => ({ name, ...withGain(figures) }));
}

/** Market / gain cells: "—" when none of the holdings has a close on record. */
function figureMoney(figures: BankFigures, value: number, currency: string): string {
  return figures.positions > 0 && figures.unvalued === figures.positions ? "—" : formatMoneyWithCode(value, currency);
}

const SECTION_ORDER: readonly SectionStatus[] = ["Live", "Potential", "Expired"];

const SECTION_NOTE: Record<SectionStatus, string> = {
  Live: "counted in the total",
  Potential: "on the Potential list · not counted in the total",
  Expired: "valued at the close on the day each one ended · not counted in the total",
};

/** Figures per bank or client for one status; Accu / Decu contracts show mark-to-market only (no purchase value). */
function GroupSummaryTable({
  rows,
  groupBy,
  variant,
  status,
  currency,
}: {
  rows: AssetAnalyticsPositionRow[];
  groupBy: GroupBy;
  variant: "holding" | "accumulator";
  status: SectionStatus;
  /** Reporting currency the figures are in. */
  currency: string;
}) {
  const isAccumulator = variant === "accumulator";
  const grouped = React.useMemo(() => groupPositions(rows, groupBy), [rows, groupBy]);
  const {
    rows: sortedRows,
    toggle,
    directionFor,
  } = useTableSort(grouped, GROUP_SORT_ACCESSORS);
  const totals = React.useMemo(() => {
    const sum = emptyFigures();
    for (const row of rows) addToFigures(sum, row);
    return withGain(sum);
  }, [rows]);
  const muted = status !== "Live";

  return (
    <StickyTableScroll className="max-h-[max(20rem,calc(100dvh-20rem))]">
      <table className={cn("w-full border-collapse text-sm", isAccumulator ? "min-w-[560px]" : "min-w-[720px]")}>
        <thead>
          <tr>
            <SortableTh
              label={groupBy === "client" ? "Client" : "Bank Name"}
              direction={directionFor("name")}
              onSort={() => toggle("name")}
            />
            <SortableTh
              label={isAccumulator ? "Contracts" : "Positions"}
              align="right"
              direction={directionFor("positions")}
              onSort={() => toggle("positions")}
            />
            <SortableTh
              label="Quantity"
              align="right"
              direction={directionFor("quantity")}
              onSort={() => toggle("quantity")}
            />
            {isAccumulator ? null : (
              <SortableTh
                label={`Purchase Value (${currency})`}
                align="right"
                direction={directionFor("purchaseValue")}
                onSort={() => toggle("purchaseValue")}
              />
            )}
            <SortableTh
              label={isAccumulator ? `Mark-to-market (${currency})` : `Market Value (${currency})`}
              align="right"
              direction={directionFor("marketValue")}
              onSort={() => toggle("marketValue")}
            />
            {isAccumulator ? null : (
              <SortableTh
                label={`Gain / Loss (${currency})`}
                align="right"
                direction={directionFor("gainLoss")}
                onSort={() => toggle("gainLoss")}
              />
            )}
          </tr>
        </thead>
        <tbody>
          {sortedRows.map((row, index) => (
            <tr
              key={row.name}
              className={cn("border-t border-border/60", index % 2 === 1 && "bg-muted/20", muted && "text-muted-foreground")}
            >
              <td className="px-3 py-2 font-medium">{row.name}</td>
              <td className="px-3 py-2 text-right tabular-nums">{row.positions}</td>
              <td className="px-3 py-2 text-right tabular-nums">
                {formatQuantity(row.quantity)}
              </td>
              {isAccumulator ? null : (
                <td className="px-3 py-2 text-right tabular-nums">
                  {formatMoneyWithCode(row.purchaseValueUsd, currency)}
                </td>
              )}
              <td className={cn("px-3 py-2 text-right tabular-nums", isAccumulator && !muted && gainClass(row.marketValueUsd))}>
                {figureMoney(row, row.marketValueUsd, currency)}
              </td>
              {isAccumulator ? null : (
                <td className={cn("px-3 py-2 text-right tabular-nums", !muted && gainClass(row.gainLossUsd))}>
                  {figureMoney(row, row.gainLossUsd, currency)}
                </td>
              )}
            </tr>
          ))}
        </tbody>
        <tfoot>
          <tr className="border-t border-border bg-muted/50 font-semibold">
            <td className="px-3 py-2.5">{muted ? `${status} subtotal` : "Total"}</td>
            <td className="px-3 py-2.5 text-right tabular-nums">{totals.positions}</td>
            <td className="px-3 py-2.5 text-right tabular-nums">
              {formatQuantity(totals.quantity)}
            </td>
            {isAccumulator ? null : (
              <td className="px-3 py-2.5 text-right tabular-nums">
                {formatMoneyWithCode(totals.purchaseValueUsd, currency)}
              </td>
            )}
            <td className={cn("px-3 py-2.5 text-right tabular-nums", isAccumulator && !muted && gainClass(totals.marketValueUsd))}>
              {figureMoney(totals, totals.marketValueUsd, currency)}
            </td>
            {isAccumulator ? null : (
              <td className={cn("px-3 py-2.5 text-right tabular-nums", !muted && gainClass(totals.gainLossUsd))}>
                {figureMoney(totals, totals.gainLossUsd, currency)}
              </td>
            )}
          </tr>
        </tfoot>
      </table>
    </StickyTableScroll>
  );
}

/** One table per status: Live first (the only one counted), then Potential and Expired on their own. */
function GroupSummarySections({
  rows,
  groupBy,
  variant,
  currency,
}: {
  rows: AssetAnalyticsPositionRow[];
  groupBy: GroupBy;
  variant: "holding" | "accumulator";
  currency: string;
}) {
  const unit = variant === "accumulator" ? "contract" : "position";
  const sections = SECTION_ORDER.flatMap((status) => {
    const sectionRows = rows.filter((row) => row.status === status);
    return sectionRows.length > 0 ? [{ status, rows: sectionRows }] : [];
  });

  return (
    <div className="space-y-5">
      {sections.map((section) => {
        const groups = new Set(section.rows.map(GROUP_KEY[groupBy])).size;
        return (
          <section key={section.status} className="space-y-2">
            <div className="flex flex-wrap items-center gap-x-2 gap-y-1">
              <span
                className={cn(
                  "inline-block whitespace-nowrap rounded-full px-2.5 py-0.5 font-semibold text-xs ring-1 ring-inset",
                  section.status === "Live" ? LIVE_TAG_CLASS : STATUS_TAG_CLASS[section.status],
                )}
              >
                {section.status}
              </span>
              <span className="font-medium text-sm">
                {section.rows.length} {unit}
                {section.rows.length === 1 ? "" : "s"} · {groups} {groupBy}
                {groups === 1 ? "" : "s"}
              </span>
              <span className="text-muted-foreground text-xs">{SECTION_NOTE[section.status]}</span>
            </div>
            <GroupSummaryTable
              rows={section.rows}
              groupBy={groupBy}
              variant={variant}
              status={section.status}
              currency={currency}
            />
          </section>
        );
      })}
    </div>
  );
}

const LIVE_TAG_CLASS = "bg-emerald-600/10 text-emerald-700 ring-emerald-600/20 dark:text-emerald-300";

const STATUS_TAG_CLASS: Record<"Potential" | "Expired", string> = {
  Potential:
    "bg-amber-600/10 text-amber-800 ring-amber-600/20 dark:text-amber-300",
  Expired:
    "bg-indigo-600/10 text-indigo-700 ring-indigo-600/20 dark:text-indigo-300",
};

function StatusTag({ row }: { row: AssetAnalyticsPositionRow }) {
  if (row.status === "Live") return null;
  const title =
    row.status === "Expired"
      ? [
          row.endedOn ? `Ended ${row.endedOn}` : "",
          row.valuedOn ? `valued at the close of ${row.valuedOn}` : "",
          "not included in totals",
        ]
          .filter(Boolean)
          .join(" · ")
      : "On Potential — not included in totals";
  return (
    <span
      title={title}
      className={cn(
        "ml-2 inline-block whitespace-nowrap rounded-full px-2 py-0.5 font-semibold text-[10px] ring-1 ring-inset",
        STATUS_TAG_CLASS[row.status],
      )}
    >
      {row.status}
    </span>
  );
}

function gainClass(value: number | null) {
  if (value === null) return "";
  if (value > 0) return "text-emerald-600 dark:text-emerald-400";
  if (value < 0) return "text-red-600 dark:text-red-400";
  return "";
}

function PositionsTable({
  rows,
  totals,
  variant,
  currency,
}: {
  rows: AssetAnalyticsPositionRow[];
  totals: AssetAnalyticsPositionsTotals | null;
  variant: "holding" | "accumulator";
  /** Reporting currency the figures are in. */
  currency: string;
}) {
  const { rows: sortedRows, toggle, directionFor } = useTableSort(rows, SORT_ACCESSORS);
  const isAccumulator = variant === "accumulator";
  const leadColumns = isAccumulator ? 5 : 4;

  return (
    <StickyTableScroll className="max-h-[max(20rem,calc(100dvh-24rem))]">
      <table className="w-full min-w-[820px] border-collapse text-sm">
        <thead>
          <tr>
            <SortableTh label="Ref ID" direction={directionFor("refId")} onSort={() => toggle("refId")} />
            <SortableTh label="Client" direction={directionFor("clientName")} onSort={() => toggle("clientName")} />
            {isAccumulator ? <SortableTh label="Contract" /> : null}
            <SortableTh label="Bank" direction={directionFor("bankName")} onSort={() => toggle("bankName")} />
            <SortableTh label="Trade Date" direction={directionFor("tradeDate")} onSort={() => toggle("tradeDate")} />
            <SortableTh label="Quantity" align="right" direction={directionFor("quantity")} onSort={() => toggle("quantity")} />
            {isAccumulator ? null : (
              <SortableTh
                label={`Purchase Value (${currency})`}
                align="right"
                direction={directionFor("purchaseValue")}
                onSort={() => toggle("purchaseValue")}
              />
            )}
            <SortableTh
              label={isAccumulator ? `Mark-to-market (${currency})` : `Market Value (${currency})`}
              align="right"
              direction={directionFor("marketValue")}
              onSort={() => toggle("marketValue")}
            />
            {isAccumulator ? null : (
              <SortableTh label="Gain / Loss" align="right" direction={directionFor("gainLoss")} onSort={() => toggle("gainLoss")} />
            )}
          </tr>
        </thead>
        <tbody>
          {sortedRows.map((row, index) => (
            <tr
              key={`${row.refId}-${row.status}-${index}`}
              className={cn("border-t border-border/60", index % 2 === 1 && "bg-muted/20", !row.counted && "text-muted-foreground")}
            >
              <td className="px-3 py-2 whitespace-nowrap">{row.refId}</td>
              {/* Long client names wrap so the amount columns never get pushed off-screen. */}
              <td className="min-w-[10rem] max-w-[15rem] px-3 py-2 font-medium leading-snug">
                {row.clientName}
                <StatusTag row={row} />
              </td>
              {isAccumulator ? (
                <td className="max-w-[14rem] px-3 py-2 leading-snug">
                  <span className="mr-1.5 inline-block rounded-full bg-muted px-1.5 py-0.5 font-semibold text-[10px]">
                    {row.kind === "decumulator" ? "Decu" : "Accu"}
                  </span>
                  {row.contract || "—"}
                </td>
              ) : null}
              <td className="px-3 py-2 whitespace-nowrap">{row.bankName}</td>
              <td className="px-3 py-2 whitespace-nowrap">
                {row.tradeDate}
                {row.endedOn ? <span className="block text-[11px]">ended {row.endedOn}</span> : null}
              </td>
              <td className="px-3 py-2 text-right tabular-nums">{row.quantityFmt}</td>
              {isAccumulator ? null : (
                <td className="px-3 py-2 text-right whitespace-nowrap tabular-nums">{row.purchaseValueUsd}</td>
              )}
              <td
                className={cn("px-3 py-2 text-right whitespace-nowrap tabular-nums", isAccumulator && row.counted && gainClass(row.marketValueUsdNum))}
                title={row.valuedOn ? `Close of ${row.valuedOn}` : undefined}
              >
                {row.marketValueUsd}
              </td>
              {isAccumulator ? null : (
                <td className={cn("px-3 py-2 text-right whitespace-nowrap tabular-nums", row.counted && gainClass(row.gainLoss))}>
                  {row.gainLossFmt}
                </td>
              )}
            </tr>
          ))}
          {totals ? (
            <tr className="border-t border-border bg-muted/50 font-semibold">
              <td className="px-3 py-2.5" colSpan={leadColumns}>
                Total <span className="font-normal text-muted-foreground text-xs">(Live)</span>
              </td>
              <td className="px-3 py-2.5 text-right whitespace-nowrap tabular-nums">
                {formatQuantity(totals.quantity)}
              </td>
              {isAccumulator ? null : (
                <td className="px-3 py-2.5 text-right whitespace-nowrap tabular-nums">{totals.purchaseValueUsdFmt}</td>
              )}
              <td className={cn("px-3 py-2.5 text-right whitespace-nowrap tabular-nums", isAccumulator && gainClass(totals.marketValueUsd))}>
                {totals.marketValueUsdFmt}
              </td>
              {isAccumulator ? null : (
                <td className={cn("px-3 py-2.5 text-right whitespace-nowrap tabular-nums", gainClass(totals.gainLoss))}>
                  {totals.gainLossFmt}
                </td>
              )}
            </tr>
          ) : null}
        </tbody>
      </table>
    </StickyTableScroll>
  );
}

function ExcludedNote({ rows }: { rows: AssetAnalyticsPositionRow[] }) {
  const potential = rows.filter((row) => row.status === "Potential").length;
  const expired = rows.filter((row) => row.status === "Expired").length;
  if (potential === 0 && expired === 0) return null;
  const parts = [
    potential > 0 ? `${potential} Potential` : "",
    expired > 0 ? `${expired} Expired` : "",
  ].filter(Boolean);
  return (
    <p className="text-muted-foreground text-xs">
      Totals count Live holdings only — {parts.join(" and ")} listed but not summed.
      {expired > 0 ? " Expired holdings are valued at the underlying's close on the day they ended." : ""}
    </p>
  );
}

export function AssetAnalyticsPositionsSheet({
  open,
  onOpenChange,
  target,
  banks,
  includeExpired,
  onIncludeExpiredChange,
}: {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  target: AssetAnalyticsPositionsTarget | null;
  /** Active bank filter from the parent report (empty when All). */
  banks: string[];
  /** Shared with the structures panel: list expired holdings (tagged, never summed). */
  includeExpired: boolean;
  onIncludeExpiredChange: (next: boolean) => void;
}) {
  const banksKey = banks.join("|");
  const [mode, setMode] = React.useState<ViewMode>("bank");
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState<string | null>(null);
  const [data, setData] = React.useState<AssetAnalyticsPositionsData | null>(null);

  // Opening, closing or retargeting starts from a clean slate (adjusted during render, not in an effect).
  const isAccumulatorTarget = target?.assetClassSlug === ACCUMULATORS_TAB_SLUG;
  useRenderEffect([open, target, banksKey], () => {
    setMode("bank");
  });
  useRenderEffect([open, target, banksKey, includeExpired], () => {
    setData(null);
    setError(null);
    setLoading(Boolean(open && target));
  });

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

    const controller = new AbortController();

    fetchAssetAnalyticsPositionsClient(target.tickerId, target.assetClassSlug, banks, controller.signal, includeExpired)
      .then(setData)
      .catch((err: unknown) => {
        if (controller.signal.aborted) return;
        setError(errorMessageOr(err, "Could not load positions."));
      })
      .finally(() => {
        if (!controller.signal.aborted) setLoading(false);
      });

    return () => controller.abort();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [open, target, banksKey, includeExpired]);

  const positions = React.useMemo(() => data?.positions ?? [], [data]);
  const accumulators = data?.accumulators ?? [];
  const showsLifecycle = target?.assetClassSlug === STRUCTURE_TAB_SLUG || isAccumulatorTarget;
  const currency = data?.code ?? REPORT_DEFAULT_CURRENCY;

  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-muted-foreground text-[10px] font-semibold tracking-widest uppercase">
            Positions
          </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">
              <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">Underlying Positions</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">
            Individual holding rows behind this ticker&apos;s{" "}
            {target?.assetClass ?? ""} tile.
          </SheetDescription>
        </div>

        <div className="flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto px-4 py-4">
          <section className="flex flex-col gap-3 rounded-2xl border border-border/60 bg-card p-3 shadow-sm">
            <div className="flex flex-wrap items-center justify-between gap-2">
              <div
                className="inline-flex w-fit gap-0.5 rounded-lg border border-border/60 bg-muted/40 p-1"
                role="tablist"
                aria-label="Positions view"
              >
                <button
                  type="button"
                  role="tab"
                  aria-selected={mode === "bank"}
                  className={segmentClass(mode === "bank")}
                  onClick={() => setMode("bank")}
                >
                  By bank
                </button>
                <button
                  type="button"
                  role="tab"
                  aria-selected={mode === "client"}
                  className={segmentClass(mode === "client")}
                  onClick={() => setMode("client")}
                >
                  By client
                </button>
                {/* Holdings are read through By bank / By client only; Accu / Decu keep their contract list. */}
                {isAccumulatorTarget ? (
                  <button
                    type="button"
                    role="tab"
                    aria-selected={mode === "detail"}
                    className={segmentClass(mode === "detail")}
                    onClick={() => setMode("detail")}
                  >
                    Contracts
                  </button>
                ) : null}
                {target?.assetClassSlug === DERIVATIVES_TAB_SLUG ? (
                  <button
                    type="button"
                    role="tab"
                    aria-selected={mode === "options"}
                    className={segmentClass(mode === "options")}
                    onClick={() => setMode("options")}
                  >
                    Options
                  </button>
                ) : null}
              </div>
              {showsLifecycle ? <ShowExpiredToggle checked={includeExpired} onChange={onIncludeExpiredChange} /> : null}
            </div>

            {target ? (
              <div className="grid gap-2 sm:grid-cols-3">
                <InfoChip label="ISIN" value={target.tickerDisplay} mono />
                <InfoChip
                  label="Name"
                  value={nameWithoutLeadingIsin(target.productName || target.tickerDisplay, target.tickerDisplay)}
                />
                <InfoChip label="Asset Type" value={target.assetClass} />
              </div>
            ) : null}
          </section>

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

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

              {!loading && !error ? (
                positions.length === 0 && accumulators.length === 0 ? (
                  <p className="text-sm text-muted-foreground">
                    No underlying positions found.
                  </p>
                ) : mode === "bank" || mode === "client" ? (
                  <GroupSummarySections
                    rows={isAccumulatorTarget ? accumulators : positions}
                    groupBy={mode}
                    variant={isAccumulatorTarget ? "accumulator" : "holding"}
                    currency={currency}
                  />
                ) : (
                  <div className="space-y-5">
                    {positions.length > 0 ? (
                      <div className="space-y-2">
                        <PositionsTable rows={positions} totals={data?.totals ?? null} variant="holding" currency={currency} />
                        <ExcludedNote rows={positions} />
                      </div>
                    ) : null}
                    {accumulators.length > 0 ? (
                      <div className="space-y-2">
                        <p className="font-semibold text-sm">
                          Accumulators &amp; decumulators{" "}
                          <span className="font-normal text-muted-foreground text-xs">on this underlying · mark-to-market</span>
                        </p>
                        <PositionsTable
                          rows={accumulators}
                          totals={data?.accumulatorTotals ?? null}
                          variant="accumulator"
                          currency={currency}
                        />
                        <ExcludedNote rows={accumulators} />
                      </div>
                    ) : null}
                  </div>
                )
              ) : null}
            </>
          )}
        </div>
      </SheetContent>
    </Sheet>
  );
}
