"use client";

import { toastApiError } from "@/lib/toast-api-error";
import * as React from "react";
import { resolveCustomerTenant } from "@/app/customer/_lib/resolve-customer-tenant";
import Link from "next/link";
import { useParams, usePathname } from "next/navigation";
import {
  Check,
  Download,
  HelpCircle,
  Loader2,
  RefreshCw,
  X,
  XCircle,
} from "lucide-react";
import { toast } from "sonner";

import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { ErrorBanner } from "@/components/shared/error-banner";
import { Table, TableBody, TableCell, TableFooter, TableRow } from "@/components/ui/table";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import { TransactionDetailSheet } from "@/components/customer/transaction-detail-sheet";
import type { TransactionRowBase } from "@/components/customer/transaction-detail-types";
import { formatAmount, formatPlainAmount } from "@/lib/format/numbers";
import { cn } from "@/lib/utils";

import {
  CustomerFieldsButton,
  CustomerFieldsPanel,
} from "@/app/customer/_components/customer-fields-panel";
import type { CustomerColumnPrefs } from "@/app/customer/_lib/customer-grid-columns";
import { useCustomerTableColumnPrefs } from "@/app/customer/_lib/use-customer-table-column-prefs";

import {
  runStructuredProductAction,
  saveStructuredProductColumnPrefsClient,
} from "../../_lib/structured-product-api";
import { exportStructuredProducts } from "../../_lib/structured-product-export";
import type {
  StructuredProductActionRequest,
  StructuredProductQuery,
  StructuredProductReportRow,
  StructuredProductSortColumn,
  StructuredProductStructureTotals,
} from "../../_lib/structured-product-types";
import {
  DEFAULT_STRUCTURED_PRODUCT_PAGE_SIZE,
  useStructuredProductList,
} from "../../_lib/use-structured-product-list";
import { buildStructuredProductPageSearchParams } from "../../_lib/parse-structured-product-url-bootstrap";
import {
  STRUCTURED_PRODUCT_FIELDS_CATALOG,
  STRUCTURED_PRODUCT_LOCKED_KEYS,
  STRUCTURED_PRODUCT_TOTAL_TOGGLE_BY_FIELD,
  type StructuredProductColumnDef,
  type StructuredProductTotalToggleKey,
  resolveStructuredProductVisibleColumns,
} from "./structured-product-columns";
import { usePortfolioScopePageReset } from "@/app/customer/_lib/admin/use-portfolio-scope-page-reset";
import type { ImpersonationScopeChangedDetail } from "@/app/customer/_lib/admin/impersonation-scope";
import {
  defaultStructuredProductReportFilters,
  type StructuredProductDisplayMode,
  type StructuredProductLifecycle,
  type StructuredProductReportFilters,
  type StructuredProductSortOrder,
} from "./schema";
import { StructuredProductFiltersDialog } from "./structured-product-filters-dialog";
import { ReportLoadingPanel } from "@/app/customer/[tenant]/reports/_shared/components/report-loading-panel";
import { ConvertedTotalValueWithTooltip } from "@/app/customer/[tenant]/reports/_shared/components/converted-total-value-with-tooltip";
import {
  ReportPageNavigation,
  ReportRecordsPerPage,
} from "@/app/customer/[tenant]/reports/_shared/components/report-table-chrome";
import {
  groupStructuredProductRows,
  reportCellClass,
  reportCellValue,
  RIGHT_ALIGNED_FIELDS,
  StructuredProductCell,
  UNDERLYING_FIELDS,
} from "./structured-product-cells";
import { resolveClientPageCount } from "@/lib/list-pagination";
import { StructuredProductTableHeader } from "./structured-product-table-header";
import { StructuredProductChartsPanel } from "./structured-product-charts";
import { useStructuredProductViewData } from "./use-structured-product-view-data";

const PAGE_SIZE_OPTIONS = [10, 25, 50, 100] as const;

const lifecycleOptions: Array<{ id: StructuredProductLifecycle; label: string }> = [
  { id: "live", label: "Live" },
  { id: "potential", label: "Potential" },
  { id: "expired", label: "Expired" },
];

const displayOptions: Array<{ id: StructuredProductDisplayMode; label: string }> = [
  { id: "graph", label: "Graph" },
  { id: "report", label: "Report" },
];

function segmentClass(active: boolean) {
  return cn(
    "h-8 shrink-0 rounded-md px-3 font-semibold text-xs transition-colors",
    active
      ? "bg-emerald-600 text-white shadow-sm"
      : "text-muted-foreground hover:bg-background/80 hover:text-foreground",
  );
}

function footerConvertedBreakdowns(
  field: StructuredProductColumnDef["field"],
  totals: StructuredProductStructureTotals,
) {
  if (field === "Notional") return totals.breakdowns?.notional;
  if (field === "IndicativeCoupon") return totals.breakdowns?.indicativeCoupon;
  if (field === "IndicativeAnnualCoupon") return totals.breakdowns?.indicativeAnnualCoupon;
  return undefined;
}

const STRUCTURED_PRODUCT_DETAIL_CONFIG = {
  entityLabel: "Structured product transaction",
  showActions: false,
} as const;

function fieldText(
  row: StructuredProductReportRow,
  field: keyof StructuredProductReportRow["values"],
): string {
  const value = row.values[field];
  if (value == null || value === "") return "";
  return String(value).trim();
}

function fieldNumber(
  row: StructuredProductReportRow,
  field: keyof StructuredProductReportRow["values"],
): number {
  const raw = row.values[field];
  if (typeof raw === "number") return Number.isFinite(raw) ? raw : 0;
  if (typeof raw === "string") {
    const parsed = Number.parseFloat(raw.replace(/,/g, ""));
    return Number.isFinite(parsed) ? parsed : 0;
  }
  return 0;
}

function toStructuredProductTransactionDetailRow(row: StructuredProductReportRow): TransactionRowBase {
  return {
    id: row.id,
    refId: fieldText(row, "AUid1") || fieldText(row, "s_isinInit") || row.productId || row.id,
    placementDate: fieldText(row, "TradeDate") || fieldText(row, "SettlementDate"),
    bank: fieldText(row, "s_bname") || "—",
    ticker: fieldText(row, "UnderlyingISIN1") || fieldText(row, "s_isinInit") || "—",
    name: row.product.name || fieldText(row, "Underlying1") || fieldText(row, "Issuer") || "—",
    type: fieldText(row, "product_typeAbsolute") || "Structured Product",
    executionType: fieldText(row, "Issuer") || "—",
    transaction: fieldText(row, "product_typeAbsolute") || "Structure",
    price: fieldNumber(row, "StrikeLevel") || fieldNumber(row, "InitialLevel") || fieldNumber(row, "CMP"),
    quantity: 0,
    currency: fieldText(row, "CurrencyName") || "—",
    amount: row.raw.notional || fieldNumber(row, "Notional"),
  };
}

/** Accumulator-style strip: TOTAL + USD / EUR native Notional amounts. */
function NativeCurrencyTotalsStrip({
  amountsByCurrency,
}: {
  amountsByCurrency: Record<string, number>;
}) {
  const entries = Object.entries(amountsByCurrency)
    .filter(([, total]) => Number.isFinite(total))
    .map(([currency, total]) => ({ currency, total }));
  if (entries.length === 0) return null;

  return (
    <div className="overflow-hidden rounded-xl border border-border/80 bg-card shadow-sm">
      <div className="flex items-center gap-x-4 gap-y-1 overflow-x-auto px-4 py-2.5 sm:px-5">
        <span className="shrink-0 font-semibold text-[11px] text-emerald-700 uppercase tracking-wider dark:text-emerald-400">
          Total
        </span>
        <ul className="flex min-w-max items-center gap-x-5 gap-y-1">
          {entries.map(({ currency, total }) => (
            <li key={currency} className="shrink-0 whitespace-nowrap text-sm tabular-nums">
              <span className="font-bold text-foreground">{currency}</span>
              <span className="text-muted-foreground"> </span>
              <span className="font-semibold text-emerald-700 dark:text-emerald-400">
                {formatAmount(total, { minimumFractionDigits: 0, maximumFractionDigits: 0 })}
              </span>
            </li>
          ))}
        </ul>
      </div>
    </div>
  );
}

/** Accumulator-style summary cards for reporting-currency totals. */
function StructuredProductTotalsCards({
  totalCount,
  totals,
  visibleToggles,
}: {
  totalCount: number;
  totals: StructuredProductStructureTotals;
  visibleToggles: Record<StructuredProductTotalToggleKey, boolean>;
}) {
  const currency = totals.currencyCode ? ` (${totals.currencyCode})` : "";
  const cards: Array<{ key: string; label: string; value: React.ReactNode }> = [
    {
      key: "structures",
      label: "Total structures",
      value: formatPlainAmount(totalCount),
    },
  ];

  if (visibleToggles.totalNotional) {
    cards.push({
      key: "notional",
      label: `Total notional${currency}`,
      value: (
        <ConvertedTotalValueWithTooltip
          value={totals.convertedTotal}
          currencyCode={totals.currencyCode}
          breakdowns={totals.breakdowns?.notional}
        />
      ),
    });
  }
  if (visibleToggles.totalIndicativeCoupon) {
    cards.push({
      key: "indicativeCoupon",
      label: `Indicative coupon${currency}`,
      value: (
        <ConvertedTotalValueWithTooltip
          value={totals.convertedIndicativeCoupon}
          currencyCode={totals.currencyCode}
          breakdowns={totals.breakdowns?.indicativeCoupon}
        />
      ),
    });
  }
  if (visibleToggles.totalIndicativeAnnualCoupon) {
    cards.push({
      key: "indicativeAnnualCoupon",
      label: `Indicative annual coupon${currency}`,
      value: (
        <ConvertedTotalValueWithTooltip
          value={totals.convertedIndicativeAnnualCoupon}
          currencyCode={totals.currencyCode}
          breakdowns={totals.breakdowns?.indicativeAnnualCoupon}
        />
      ),
    });
  }

  const gridCols =
    cards.length <= 2
      ? "grid-cols-2"
      : cards.length === 3
        ? "grid-cols-2 sm:grid-cols-3"
        : "grid-cols-2 sm:grid-cols-4";

  return (
    <div className={cn("grid gap-3", gridCols)}>
      {cards.map((card) => (
        <Card key={card.key} className="min-w-0 overflow-hidden border-border/80 py-0 shadow-sm">
          <CardContent className="py-3">
            <p className="truncate font-medium text-[11px] text-muted-foreground uppercase tracking-wider">
              {card.label}
            </p>
            <p className="mt-1 truncate font-semibold text-base tabular-nums">{card.value}</p>
          </CardContent>
        </Card>
      ))}
    </div>
  );
}

function footerConvertedAmount(
  field: StructuredProductColumnDef["field"],
  totals: StructuredProductStructureTotals | null,
): number | null {
  if (!totals) return null;
  if (field === "Notional") return totals.convertedTotal;
  if (field === "IndicativeCoupon") return totals.convertedIndicativeCoupon;
  if (field === "IndicativeAnnualCoupon") return totals.convertedIndicativeAnnualCoupon;
  return null;
}

export function StructuredProductView({
  showPotentialActions = false,
  initialLifecycle = "live",
  initialFilters = defaultStructuredProductReportFilters,
  initialListData = null,
  initialListError = null,
  initialListQueryKey = "",
  initialPage = 1,
  initialPageSize = DEFAULT_STRUCTURED_PRODUCT_PAGE_SIZE,
  initialSortColumn = null,
  initialSortDirection = "desc",
}: {
  showPotentialActions?: boolean;
  initialLifecycle?: StructuredProductLifecycle;
  initialFilters?: StructuredProductReportFilters;
  initialListData?: import("../../_lib/structured-product-types").StructuredProductListData | null;
  initialListError?: string | null;
  initialListQueryKey?: string;
  initialPage?: number;
  initialPageSize?: number;
  initialSortColumn?: StructuredProductSortColumn | null;
  initialSortDirection?: StructuredProductSortOrder;
}) {
  const params = useParams<{ tenant?: string }>();
  const pathname = usePathname();
  const tenant =
    typeof params?.tenant === "string" && params.tenant.trim() ? params.tenant.trim() : resolveCustomerTenant();
  const [displayMode, setDisplayMode] =
    React.useState<StructuredProductDisplayMode>("report");
  const [lifecycle, setLifecycle] =
    React.useState<StructuredProductLifecycle>(initialLifecycle);
  const [filters, setFilters] = React.useState<StructuredProductReportFilters>(initialFilters);
  const [inlineFilters, setInlineFilters] = React.useState(() => ({
    isin: initialFilters.isin,
    underlying: initialFilters.underlying,
    underlyingIsin: initialFilters.underlyingIsin,
    productTypes: initialFilters.productTypes,
  }));
  const [page, setPage] = React.useState(initialPage);
  const [pageSize, setPageSize] = React.useState(initialPageSize);
  const [sortColumn, setSortColumn] =
    React.useState<StructuredProductSortColumn | null>(initialSortColumn);
  const [sortDirection, setSortDirection] =
    React.useState<StructuredProductSortOrder>(initialSortDirection);
  const suppressUrlSyncRef = React.useRef(false);

  React.useEffect(() => {
    const timer = window.setTimeout(() => {
      setFilters((current) => {
        if (
          current.isin === inlineFilters.isin &&
          current.underlying === inlineFilters.underlying &&
          current.underlyingIsin === inlineFilters.underlyingIsin &&
          current.productTypes.join("\u0000") === inlineFilters.productTypes.join("\u0000")
        ) {
          return current;
        }
        return { ...current, ...inlineFilters };
      });
      setPage(1);
    }, 400);

    return () => window.clearTimeout(timer);
  }, [inlineFilters]);

  // Keep the browser URL in sync so searches/filters are shareable and survive refresh.
  // Use history.replaceState (not router.replace) to avoid remounting the RSC page mid-edit.
  React.useEffect(() => {
    if (suppressUrlSyncRef.current) return;

    const params = buildStructuredProductPageSearchParams({
      lifecycle,
      filters,
      page,
      pageSize,
      sortColumn,
      sortDirection,
    });
    const qs = params.toString();
    const nextUrl = qs ? `${pathname}?${qs}` : pathname;
    const currentUrl = `${window.location.pathname}${window.location.search}`;
    if (nextUrl !== currentUrl) {
      window.history.replaceState(window.history.state, "", nextUrl);
    }
  }, [filters, lifecycle, page, pageSize, pathname, sortColumn, sortDirection]);

  // Portfolio Scope Apply / banner Clear: drop cashflow deep-link filters so
  // cookie scope drives the list instead of pinned isin/clientIds.
  usePortfolioScopePageReset(
    React.useCallback((_detail: ImpersonationScopeChangedDetail) => {
      suppressUrlSyncRef.current = true;
      setFilters(defaultStructuredProductReportFilters);
      setInlineFilters({
        isin: defaultStructuredProductReportFilters.isin,
        underlying: defaultStructuredProductReportFilters.underlying,
        underlyingIsin: defaultStructuredProductReportFilters.underlyingIsin,
        productTypes: defaultStructuredProductReportFilters.productTypes,
      });
      setSortColumn(null);
      setSortDirection("desc");
      setPage(1);
      window.history.replaceState(window.history.state, "", pathname);
      window.setTimeout(() => {
        suppressUrlSyncRef.current = false;
      }, 0);
    }, [pathname]),
  );

  const [isExporting, setIsExporting] = React.useState(false);
  const [pendingAction, setPendingAction] = React.useState<string | null>(null);
  const [fieldsOpen, setFieldsOpen] = React.useState(false);
  const [detailRow, setDetailRow] = React.useState<StructuredProductReportRow | null>(null);
  const [detailOpen, setDetailOpen] = React.useState(false);

  const query = React.useMemo<StructuredProductQuery>(
    () => ({
      lifecycle,
      page,
      pageSize,
      userIds: filters.userIds.length ? filters.userIds : undefined,
      clientIds: filters.clientIds.length ? filters.clientIds : undefined,
      bankIds: filters.bankIds.length ? filters.bankIds : undefined,
      observationFrom: filters.observationFrom || undefined,
      observationTo: filters.observationTo || undefined,
      nextObservationFrom: filters.nextObservationFrom || undefined,
      nextObservationTo: filters.nextObservationTo || undefined,
      couponFrom: filters.couponFrom || undefined,
      couponTo: filters.couponTo || undefined,
      currencyId: filters.currencyId ?? undefined,
      productTypes: filters.productTypes.length ? filters.productTypes : undefined,
      isin: filters.isin.trim() || undefined,
      underlying: filters.underlying.trim() || undefined,
      underlyingIsin: filters.underlyingIsin.trim() || undefined,
      earlyRedemption: filters.earlyRedemption ?? undefined,
      delivery: filters.delivery ?? undefined,
      sortColumn: sortColumn ?? undefined,
      sortDirection: sortColumn ? sortDirection : undefined,
    }),
    [filters, lifecycle, page, pageSize, sortColumn, sortDirection],
  );

  const {
    rows,
    totalCount,
    availableCurrencies,
    availableProductTypes,
    banks,
    bankError,
    columnPrefs,
    structureTotals,
    isLoading,
    errorMessage,
    refresh,
  } = useStructuredProductList(query, {
    data: initialListData,
    errorMessage: initialListError,
    queryKey: initialListQueryKey,
  });

  const {
    charts,
    graphError,
    isGraphLoading,
    setGraphRefreshKey,
  } = useStructuredProductViewData({
    displayMode,
    query,
  });

  // Intentionally recomputed from local `pageSize` state rather than reusing the
  // hook's `pageCount`: the hook derives from the server-confirmed page size, which
  // lags a page-size change by one request.
  const pageCount = resolveClientPageCount(totalCount, pageSize);

  const saveColumnPrefs = React.useCallback(async (prefs: CustomerColumnPrefs) => {
    await saveStructuredProductColumnPrefsClient(prefs);
  }, []);

  const {
    columnVisibility,
    columnOrder,
    hideAll,
    setColumnVisible,
    reorderShown,
  } = useCustomerTableColumnPrefs({
    catalog: STRUCTURED_PRODUCT_FIELDS_CATALOG,
    initialPrefs: columnPrefs,
    lockedKeys: STRUCTURED_PRODUCT_LOCKED_KEYS,
    savePrefs: saveColumnPrefs,
  });

  const visibleColumns = React.useMemo(
    () =>
      resolveStructuredProductVisibleColumns(
        columnOrder,
        columnVisibility as Record<string, boolean>,
      ),
    [columnOrder, columnVisibility],
  );

  const totalToggleVisibility = React.useMemo(
    () => ({
      totalNotional: columnVisibility.totalNotional !== false,
      totalIndicativeCoupon: columnVisibility.totalIndicativeCoupon !== false,
      totalIndicativeAnnualCoupon:
        columnVisibility.totalIndicativeAnnualCoupon !== false,
    }),
    [columnVisibility],
  );
  const anyTotalVisible =
    totalToggleVisibility.totalNotional ||
    totalToggleVisibility.totalIndicativeCoupon ||
    totalToggleVisibility.totalIndicativeAnnualCoupon;
  const hasFooterTotalAmounts = React.useMemo(() => {
    return visibleColumns.some((column) => {
      const toggleKey =
        STRUCTURED_PRODUCT_TOTAL_TOGGLE_BY_FIELD[
          column.field as keyof typeof STRUCTURED_PRODUCT_TOTAL_TOGGLE_BY_FIELD
        ];
      return toggleKey ? totalToggleVisibility[toggleKey] : false;
    });
  }, [totalToggleVisibility, visibleColumns]);

  const groupedRows = React.useMemo(() => groupStructuredProductRows(rows), [rows]);
  const shownCount = groupedRows.length;
  const rangeStart = totalCount === 0 ? 0 : (page - 1) * pageSize + 1;
  const rangeEnd = totalCount === 0 ? 0 : Math.min((page - 1) * pageSize + shownCount, totalCount);
  const rangeLabel =
    totalCount === 0
      ? ""
      : `${formatPlainAmount(rangeStart)}–${formatPlainAmount(rangeEnd)} of ${formatPlainAmount(totalCount)}`;
  const rangeSummary =
    totalCount === 0
      ? isLoading
        ? "Loading structures…"
        : "No structures match the current filters"
      : `Showing ${rangeLabel} structures`;

  React.useEffect(() => {
    if (!isLoading && totalCount > 0 && page > pageCount) {
      setPage(pageCount);
    }
  }, [isLoading, page, pageCount, totalCount]);

  const handleSort = (column: StructuredProductSortColumn) => {
    setPage(1);
    if (sortColumn === column) {
      setSortDirection((current) => (current === "asc" ? "desc" : "asc"));
    } else {
      setSortColumn(column);
      setSortDirection("asc");
    }
  };

  const handlePotentialAction = async (
    action: StructuredProductActionRequest["action"],
    id: string | null,
  ) => {
    if (!action || !id || pendingAction) return;

    setPendingAction(`${action}:${id}`);
    try {
      const result = await runStructuredProductAction({ action, id });
      if (action === "accept") {
        if (!result.url) throw new Error("The accept action did not return a destination URL.");
        const destination = new URL(result.url, window.location.origin);
        if (destination.protocol !== "http:" && destination.protocol !== "https:") {
          throw new Error("The accept action returned an invalid destination URL.");
        }
        window.open(destination.toString(), "_blank", "noopener,noreferrer");
      } else {
        refresh();
      }
      toast.success(result.message ?? `Structure ${action} completed.`);
    } catch (error) {
      toastApiError(error, "Potential action failed.");
    } finally {
      setPendingAction(null);
    }
  };

  const handleExport = async (
    format: "excel" | "csv",
    tab: StructuredProductLifecycle | "all",
  ) => {
    setIsExporting(true);
    try {
      await exportStructuredProducts({ format, tab, query });
      toast.success(`${format.toUpperCase()} export downloaded.`);
    } catch (error) {
      toastApiError(error, "Export failed.");
    } finally {
      setIsExporting(false);
    }
  };

  return (
    <div className="flex min-w-0 flex-col gap-4">
      <div className="mb-4 flex w-full min-w-0 flex-col gap-4 border-b pb-4 sm:flex-row sm:items-center">
        <div className="min-w-0 shrink-0 space-y-2">
          <div>
            <h1 className="font-semibold text-2xl tracking-tight">Structured Products</h1>
            <p className="text-muted-foreground text-sm tabular-nums">
              {rangeSummary}
              {isLoading ? " · Refreshing…" : ""}
            </p>
          </div>
          <div className="flex flex-wrap items-center gap-2">
            <div
              className="inline-flex gap-0.5 rounded-lg border border-border/60 bg-muted/40 p-1"
              role="tablist"
              aria-label="Display mode"
            >
              {displayOptions.map((option) => (
                <button
                  key={option.id}
                  type="button"
                  role="tab"
                  aria-selected={displayMode === option.id}
                  onClick={() => setDisplayMode(option.id)}
                  className={segmentClass(displayMode === option.id)}
                >
                  {option.label}
                </button>
              ))}
            </div>
            <div
              className="inline-flex gap-0.5 rounded-lg border border-border/60 bg-muted/40 p-1"
              role="tablist"
              aria-label="Lifecycle"
            >
              {lifecycleOptions.map((option) => (
                <button
                  key={option.id}
                  type="button"
                  role="tab"
                  aria-selected={lifecycle === option.id}
                  onClick={() => {
                    setLifecycle(option.id);
                    setPage(1);
                  }}
                  className={segmentClass(lifecycle === option.id)}
                >
                  {option.label}
                </button>
              ))}
            </div>
          </div>
        </div>
        <div className="flex w-full min-w-0 flex-wrap items-center justify-end gap-2 sm:ml-auto sm:w-auto">
          {displayMode === "report" ? (
            <ReportRecordsPerPage
              id="structured-product-rows-per-page"
              pageSize={pageSize}
              options={PAGE_SIZE_OPTIONS}
              onPageSizeChange={(size) => {
                setPageSize(size);
                setPage(1);
              }}
            />
          ) : null}
          {displayMode === "report" ? (
            <CustomerFieldsButton onClick={() => setFieldsOpen(true)} />
          ) : null}
          <StructuredProductFiltersDialog
            filters={filters}
            banks={banks}
            currencies={availableCurrencies}
            productTypes={availableProductTypes}
            onApply={(next) => {
              setFilters(next);
              setInlineFilters({
                isin: next.isin,
                underlying: next.underlying,
                underlyingIsin: next.underlyingIsin,
                productTypes: next.productTypes,
              });
              setPage(1);
            }}
          />
          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <Button
                variant="outline"
                size="icon-lg"
                className="h-9 w-9 shrink-0"
                disabled={isExporting}
              >
                {isExporting ? (
                  <Loader2 className="size-4 animate-spin" />
                ) : (
                  <Download className="size-4" />
                )}
                <span className="sr-only">Download</span>
              </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent align="end">
              <DropdownMenuItem onClick={() => void handleExport("excel", lifecycle)}>
                Download Excel
              </DropdownMenuItem>
              <DropdownMenuItem onClick={() => void handleExport("csv", lifecycle)}>
                Download CSV
              </DropdownMenuItem>
            </DropdownMenuContent>
          </DropdownMenu>
          <Button
            variant="outline"
            size="icon-lg"
            className="h-9 w-9 shrink-0"
            onClick={() => {
              setFilters(defaultStructuredProductReportFilters);
              setInlineFilters({
                isin: defaultStructuredProductReportFilters.isin,
                underlying: defaultStructuredProductReportFilters.underlying,
                underlyingIsin: defaultStructuredProductReportFilters.underlyingIsin,
                productTypes: defaultStructuredProductReportFilters.productTypes,
              });
              setLifecycle("live");
              setSortColumn(null);
              setSortDirection("desc");
              setPage(1);
              refresh();
              setGraphRefreshKey((value) => value + 1);
            }}
            disabled={isLoading}
          >
            <RefreshCw className={cn("size-4", isLoading && "animate-spin")} />
            <span className="sr-only">Refresh</span>
          </Button>
          <Button variant="outline" size="icon-lg" className="h-9 w-9 shrink-0" asChild>
            <Link href={`/customer/${tenant}/reports`}>
              <X className="size-4" />
              <span className="sr-only">Close</span>
            </Link>
          </Button>
        </div>
      </div>

      <ErrorBanner message={errorMessage ?? bankError} />

      {displayMode === "graph" ? (
        <StructuredProductChartsPanel
          charts={charts}
          graphError={graphError}
          isGraphLoading={isGraphLoading}
        />
      ) : (
        <>
          {structureTotals ? (
            <div className="flex flex-col gap-3">
              <NativeCurrencyTotalsStrip amountsByCurrency={structureTotals.amount} />
              <StructuredProductTotalsCards
                totalCount={totalCount}
                totals={structureTotals}
                visibleToggles={totalToggleVisibility}
              />
            </div>
          ) : null}
          <ReportLoadingPanel
            loading={isLoading}
            label="Loading structured products…"
            className={cn(isLoading && "pointer-events-none")}
          >
            <div className="overflow-x-auto rounded-lg border bg-card">
              <Table>
                <StructuredProductTableHeader
                  lifecycle={lifecycle}
                  showPotentialActions={showPotentialActions}
                  sortColumn={sortColumn}
                  sortDirection={sortDirection}
                  onSort={handleSort}
                  filters={{ ...filters, ...inlineFilters }}
                  productTypes={availableProductTypes}
                  visibleColumns={visibleColumns}
                  onFiltersChange={(next) => {
                    setInlineFilters({
                      isin: next.isin,
                      underlying: next.underlying,
                      underlyingIsin: next.underlyingIsin,
                      productTypes: next.productTypes,
                    });
                  }}
                />
                <TableBody>
                  {shownCount ? (
                    groupedRows.map((group, groupIndex) => {
                      const head = group[0];
                      return (
                        <TableRow
                          key={head.id}
                          className={cn(
                            "cursor-pointer align-middle",
                            groupIndex % 2 === 0 ? "bg-muted/5" : undefined,
                          )}
                          onClick={() => {
                            setDetailRow(head);
                            setDetailOpen(true);
                          }}
                        >
                          {lifecycle === "potential" && showPotentialActions ? (
                            <TableCell className="px-2 py-2 align-middle">
                              <div className="flex items-center gap-1">
                                <Button
                                  type="button"
                                  size="sm"
                                  variant="outline"
                                  className="h-7 border-emerald-500/30 px-2 text-emerald-700 hover:bg-emerald-500/10"
                                  disabled={pendingAction !== null}
                                  onClick={(event) => {
                                    event.stopPropagation();
                                    void handlePotentialAction(
                                      "accept",
                                      head.actionId ?? head.productId,
                                    );
                                  }}
                                  aria-label="Accept potential structure"
                                  title="Accept this record"
                                >
                                  <Check className="size-4" strokeWidth={3} />
                                </Button>
                                <Button
                                  type="button"
                                  size="sm"
                                  variant="outline"
                                  className="h-7 border-red-500/30 px-2 text-red-700 hover:bg-red-500/10"
                                  disabled={pendingAction !== null}
                                  onClick={(event) => {
                                    event.stopPropagation();
                                    void handlePotentialAction(
                                      "reject",
                                      head.actionId ?? head.productId,
                                    );
                                  }}
                                  aria-label="Reject potential structure"
                                  title="Reject this record"
                                >
                                  <XCircle className="size-4" strokeWidth={2.5} />
                                </Button>
                                {head.potentialReason ? (
                                  <TooltipProvider>
                                    <Tooltip>
                                      <TooltipTrigger asChild>
                                        <button
                                          type="button"
                                          className="inline-flex size-7 items-center justify-center rounded-md border"
                                          aria-label="Potential reason"
                                          onClick={(event) => event.stopPropagation()}
                                        >
                                          <HelpCircle className="size-3.5" />
                                        </button>
                                      </TooltipTrigger>
                                      <TooltipContent>{head.potentialReason}</TooltipContent>
                                    </Tooltip>
                                  </TooltipProvider>
                                ) : null}
                              </div>
                            </TableCell>
                          ) : null}
                          {visibleColumns.map((column) => {
                            const isUnderlying = UNDERLYING_FIELDS.has(column.field);
                            return (
                              <TableCell
                                key={column.field}
                                className={cn(
                                  "px-2 py-2 align-middle text-sm",
                                  column.field === "s_isinInit"
                                    ? "whitespace-nowrap font-mono text-[11px] font-medium tracking-tight"
                                    : column.field === "AUid1"
                                      ? "whitespace-nowrap tabular-nums text-muted-foreground"
                                      : column.field === "Issuer" ||
                                          column.field === "Industry" ||
                                          column.field === "Sector" ||
                                          column.field === "Underlying1"
                                        ? "max-w-[14rem] whitespace-normal"
                                        : "whitespace-nowrap",
                                  RIGHT_ALIGNED_FIELDS.has(column.field) && "text-right tabular-nums",
                                  !isUnderlying && reportCellClass(head, column.field),
                                )}
                              >
                                {column.field === "AUid1" ? (
                                  reportCellValue(head, "AUid1") ||
                                  String(rangeStart + groupIndex)
                                ) : isUnderlying ? (
                                  <div className="flex min-w-0 flex-col gap-0">
                                    {group.map((member, memberIndex) => (
                                      <div
                                        key={`${member.id}-${column.field}`}
                                        className={cn(
                                          "py-0.5 leading-snug",
                                          memberIndex > 0 && "border-t border-border/40 pt-1",
                                          reportCellClass(member, column.field),
                                        )}
                                      >
                                        <StructuredProductCell row={member} field={column.field} />
                                      </div>
                                    ))}
                                  </div>
                                ) : (
                                  <StructuredProductCell row={head} field={column.field} />
                                )}
                              </TableCell>
                            );
                          })}
                        </TableRow>
                      );
                    })
                  ) : !isLoading ? (
                    <TableRow>
                      <TableCell
                        colSpan={
                          visibleColumns.length
                          + (lifecycle === "potential" && showPotentialActions ? 1 : 0)
                        }
                        className="h-24 text-center text-muted-foreground text-sm"
                      >
                        No structured products match your filters.
                      </TableCell>
                    </TableRow>
                  ) : null}
                </TableBody>
                {anyTotalVisible && structureTotals && shownCount > 0 && hasFooterTotalAmounts ? (
                  <TableFooter>
                    <TableRow className="border-t bg-muted/30 hover:bg-muted/30">
                      {lifecycle === "potential" && showPotentialActions ? (
                        <TableCell className="px-2 py-2" />
                      ) : null}
                      {visibleColumns.map((column) => {
                        const toggleKey =
                          STRUCTURED_PRODUCT_TOTAL_TOGGLE_BY_FIELD[
                            column.field as keyof typeof STRUCTURED_PRODUCT_TOTAL_TOGGLE_BY_FIELD
                          ];
                        const showFieldTotal = toggleKey
                          ? totalToggleVisibility[toggleKey]
                          : false;
                        const amount = showFieldTotal
                          ? footerConvertedAmount(column.field, structureTotals)
                          : null;
                        return (
                          <TableCell
                            key={`footer-${column.field}`}
                            className={cn(
                              "px-2 py-2 align-middle text-sm",
                              RIGHT_ALIGNED_FIELDS.has(column.field) && "text-right",
                            )}
                          >
                            {amount != null ? (
                              <div className="text-right tabular-nums leading-snug">
                                <span className="block text-[11px] font-normal text-muted-foreground">
                                  Total
                                  {structureTotals.currencyCode
                                    ? ` (${structureTotals.currencyCode})`
                                    : ""}
                                </span>
                                <ConvertedTotalValueWithTooltip
                                  value={amount}
                                  currencyCode={structureTotals.currencyCode}
                                  breakdowns={footerConvertedBreakdowns(
                                    column.field,
                                    structureTotals,
                                  )}
                                />
                              </div>
                            ) : null}
                          </TableCell>
                        );
                      })}
                    </TableRow>
                  </TableFooter>
                ) : null}
              </Table>
            </div>
          </ReportLoadingPanel>

          <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
            <p className="text-muted-foreground text-sm tabular-nums">
              {totalCount === 0 ? "No results" : `Showing ${rangeLabel}`}
            </p>
            <ReportPageNavigation
              page={page}
              pageCount={totalCount === 0 ? 0 : pageCount}
              onPageChange={setPage}
              disabled={isLoading}
            />
          </div>
        </>
      )}

      <TransactionDetailSheet
        row={detailRow ? toStructuredProductTransactionDetailRow(detailRow) : null}
        open={detailOpen}
        onOpenChange={setDetailOpen}
        config={STRUCTURED_PRODUCT_DETAIL_CONFIG}
      />

      <CustomerFieldsPanel
        open={fieldsOpen}
        onOpenChange={setFieldsOpen}
        catalog={STRUCTURED_PRODUCT_FIELDS_CATALOG}
        visibility={columnVisibility as Record<string, boolean>}
        order={columnOrder}
        lockedKeys={STRUCTURED_PRODUCT_LOCKED_KEYS}
        title="Fields"
        description="Choose which columns to show and reorder. For Notional and coupon columns, use Column and Total switches separately on the same row."
        onToggle={setColumnVisible}
        onReorder={reorderShown}
        onHideAll={hideAll}
      />
    </div>
  );
}
