"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,
  ChevronsDownUp,
  ChevronsUpDown,
  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 { TableBody, TableCell, TableFooter, TableRow } from "@/components/ui/table";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
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 { useReportBankModeInvalidation } from "@/app/customer/_lib/use-report-bank-mode-invalidation";
import {
  defaultStructuredProductReportFilters,
  pickStructuredProductInlineFilters,
  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 {
  ReportLifecycleBadge,
  resolvePotentialBadge,
  resolveUpcomingBadge,
} from "@/app/customer/[tenant]/reports/_shared/components/report-lifecycle-badge";
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,
  isPhoenixEProductRow,
  PhoenixEMemoryUnderlying,
  reportCellClass,
  reportCellValue,
  RIGHT_ALIGNED_FIELDS,
  StructuredProductCell,
  UNDERLYING_FIELDS,
} from "./structured-product-cells";
import { resolveClientPageCount } from "@/lib/list-pagination";
import { StructuredProductDetailSheet } from "./structured-product-detail-sheet";
import { StructuredProductTableHeader } from "./structured-product-table-header";
import { StructuredProductChartsPanel } from "./structured-product-charts";
import { useStructuredProductViewData } from "./use-structured-product-view-data";
import {
  filterAllowedStructuredProductDisplayModes,
  filterAllowedStructuredProductLifecycles,
} from "../../_lib/structured-product-tab-permissions";

const PAGE_SIZE_OPTIONS = [10, 25, 50, 100] as const;
const TOTALS_COLLAPSED_STORAGE_KEY = "structured-product-report:totals-collapsed";
const TOTALS_COLLAPSED_EVENT = "structured-product-report:totals-collapsed-change";

function readTotalsCollapsed(): boolean {
  return window.localStorage.getItem(TOTALS_COLLAPSED_STORAGE_KEY) === "1";
}

function setTotalsCollapsed(collapsed: boolean) {
  window.localStorage.setItem(TOTALS_COLLAPSED_STORAGE_KEY, collapsed ? "1" : "0");
  window.dispatchEvent(new Event(TOTALS_COLLAPSED_EVENT));
}

function subscribeTotalsCollapsed(onChange: () => void) {
  window.addEventListener(TOTALS_COLLAPSED_EVENT, onChange);
  window.addEventListener("storage", onChange);
  return () => {
    window.removeEventListener(TOTALS_COLLAPSED_EVENT, onChange);
    window.removeEventListener("storage", onChange);
  };
}

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;
  if (field === "annualCouponCalc") return totals.breakdowns?.annualCouponCalc;
  if (field === "MaxCoupon") return totals.breakdowns?.maxCoupon;
  if (field === "marketValueApi") return totals.breakdowns?.marketValueApi;
  if (field === "profitApi") return totals.breakdowns?.profitApi;
  return undefined;
}

/** 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}
        />
      ),
    });
  }
  if (visibleToggles.totalAnnualCouponCalc) {
    cards.push({
      key: "annualCouponCalc",
      label: `Annual coupon (calc)${currency}`,
      value: (
        <ConvertedTotalValueWithTooltip
          value={totals.convertedAnnualCouponCalc}
          currencyCode={totals.currencyCode}
          breakdowns={totals.breakdowns?.annualCouponCalc}
        />
      ),
    });
  }
  if (visibleToggles.totalMaxCoupon) {
    cards.push({
      key: "maxCoupon",
      label: `Max coupon${currency}`,
      value: (
        <ConvertedTotalValueWithTooltip
          value={totals.convertedMaxCoupon}
          currencyCode={totals.currencyCode}
          breakdowns={totals.breakdowns?.maxCoupon}
        />
      ),
    });
  }
  if (visibleToggles.totalMarketValueApi) {
    cards.push({
      key: "marketValueApi",
      label: `Market value API${currency}`,
      value: (
        <ConvertedTotalValueWithTooltip
          value={totals.convertedMarketValueApi}
          currencyCode={totals.currencyCode}
          breakdowns={totals.breakdowns?.marketValueApi}
        />
      ),
    });
  }
  if (visibleToggles.totalProfitApi) {
    cards.push({
      key: "profitApi",
      label: `Profit (API)${currency}`,
      value: (
        <ConvertedTotalValueWithTooltip
          value={totals.convertedProfitApi}
          currencyCode={totals.currencyCode}
          breakdowns={totals.breakdowns?.profitApi}
        />
      ),
    });
  }

  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;
  if (field === "annualCouponCalc") return totals.convertedAnnualCouponCalc;
  if (field === "MaxCoupon") return totals.convertedMaxCoupon;
  if (field === "marketValueApi") return totals.convertedMarketValueApi;
  if (field === "profitApi") return totals.convertedProfitApi;
  return null;
}

function footerConvertedPercent(
  field: StructuredProductColumnDef["field"],
  totals: StructuredProductStructureTotals | null,
): number | null {
  if (!totals || field !== "profitApiPct") return null;
  return totals.convertedProfitApiPct;
}

export function StructuredProductView({
  showPotentialActions = false,
  allowedRoutes = [],
  initialLifecycle = "live",
  initialFilters = defaultStructuredProductReportFilters,
  initialListData = null,
  initialListError = null,
  initialListQueryKey = "",
  initialPage = 1,
  initialPageSize = DEFAULT_STRUCTURED_PRODUCT_PAGE_SIZE,
  initialSortColumn = null,
  initialSortDirection = "desc",
}: {
  showPotentialActions?: boolean;
  allowedRoutes?: readonly string[];
  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();

  // Portal Access seeds a distinct checkbox per tab (Structured Product Live/Potential/
  // Expired/Graph) — hide whichever ones this session's role hasn't granted. "Report" has no
  // checkbox of its own, so it always survives the filter once the page itself is reachable.
  const allowedLifecycleOptions = React.useMemo(
    () => filterAllowedStructuredProductLifecycles(lifecycleOptions, allowedRoutes),
    [allowedRoutes],
  );
  const allowedDisplayOptions = React.useMemo(
    () => filterAllowedStructuredProductDisplayModes(displayOptions, allowedRoutes),
    [allowedRoutes],
  );

  // "report" has no route-key gate of its own (see structured-product-tab-permissions.ts),
  // so it always survives the filter and is a safe default — no correction ever needed here.
  const [displayMode, setDisplayMode] =
    React.useState<StructuredProductDisplayMode>("report");
  // The URL/bootstrap-provided tab may not be one this role holds (e.g. a direct link to
  // ?lifecycle=potential shared before the role lost that grant) — fall back to the first
  // tab the session actually holds. allowedRoutes is a server-provided prop that doesn't
  // change over this component's lifetime, so a mount-time fallback is sufficient; no effect
  // needed to keep re-deriving it.
  const [lifecycle, setLifecycle] = React.useState<StructuredProductLifecycle>(
    allowedLifecycleOptions.some((option) => option.id === initialLifecycle)
      ? initialLifecycle
      : (allowedLifecycleOptions[0]?.id ?? initialLifecycle),
  );
  const [filters, setFilters] = React.useState<StructuredProductReportFilters>(initialFilters);
  const [inlineFilters, setInlineFilters] = React.useState(() =>
    pickStructuredProductInlineFilters(initialFilters),
  );
  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.shortName === inlineFilters.shortName &&
          current.clientNumber === inlineFilters.clientNumber &&
          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(pickStructuredProductInlineFilters(defaultStructuredProductReportFilters));
      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 totalsCollapsed = React.useSyncExternalStore(
    subscribeTotalsCollapsed,
    readTotalsCollapsed,
    () => false,
  );
  const [detailGroup, setDetailGroup] = React.useState<StructuredProductReportRow[] | null>(null);
  const [detailOpen, setDetailOpen] = React.useState(false);
  const [bankModeVersion, setBankModeVersion] = React.useState(0);

  // Parent/Child bank mode ids are two different id spaces (master parent ids vs.
  // tenant bank ids) — a bank selection made under the previous mode is meaningless
  // under the new one, so drop it and force the /banks options to refetch instead
  // of serving the previous mode's cache.
  useReportBankModeInvalidation(() => {
    setBankModeVersion((value) => value + 1);
    setFilters((current) => ({ ...current, bankIds: [] }));
    setPage(1);
  });

  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,
      shortName: filters.shortName.trim() || undefined,
      clientNumber: filters.clientNumber.trim() || 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,
    bankModeVersion,
  });

  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,
      totalAnnualCouponCalc: columnVisibility.totalAnnualCouponCalc !== false,
      totalMaxCoupon: columnVisibility.totalMaxCoupon !== false,
      totalMarketValueApi: columnVisibility.totalMarketValueApi !== false,
      totalProfitApi: columnVisibility.totalProfitApi !== false,
    }),
    [columnVisibility],
  );
  const anyTotalVisible =
    totalToggleVisibility.totalNotional ||
    totalToggleVisibility.totalIndicativeCoupon ||
    totalToggleVisibility.totalIndicativeAnnualCoupon ||
    totalToggleVisibility.totalAnnualCouponCalc ||
    totalToggleVisibility.totalMaxCoupon ||
    totalToggleVisibility.totalMarketValueApi ||
    totalToggleVisibility.totalProfitApi;
  const hasFooterTotalAmounts = React.useMemo(() => {
    return visibleColumns.some((column) => {
      if (column.field === "profitApiPct") return true;
      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`;

  // Clamp an out-of-range page (e.g. after filtering shrinks the result) while rendering.
  if (!isLoading && totalCount > 0 && page > pageCount) {
    setPage(pageCount);
  }

  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,
    scope?: StructuredProductActionRequest["scope"],
  ) => {
    if (!action || !id || pendingAction) return;

    setPendingAction(`${scope ?? "structure"}:${action}:${id}`);
    try {
      const result = await runStructuredProductAction({ action, id, scope });
      // Structure Accept opens portal mark-expired; leg Accept just stamps memory P.
      if (action === "accept" && scope !== "leg") {
        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 ??
          (scope === "leg"
            ? `Underlying memory ${action === "accept" ? "accepted" : "cleared"}.`
            : `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 h-full min-h-0 min-w-0 flex-1 flex-col gap-3">
      <div className="flex w-full min-w-0 shrink-0 flex-col gap-4 border-b pb-3 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"
            >
              {allowedDisplayOptions.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"
            >
              {allowedLifecycleOptions.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>
            {displayMode === "report" && structureTotals ? (
              <div className="inline-flex rounded-lg border border-border/60 bg-muted/40 p-1">
                <button
                  type="button"
                  aria-expanded={!totalsCollapsed}
                  title={totalsCollapsed ? "Show totals" : "Hide totals"}
                  onClick={() => setTotalsCollapsed(!totalsCollapsed)}
                  className={cn(segmentClass(false), "inline-flex items-center gap-1.5")}
                >
                  {totalsCollapsed ? (
                    <ChevronsUpDown className="size-3.5" />
                  ) : (
                    <ChevronsDownUp className="size-3.5" />
                  )}
                  {totalsCollapsed ? "Expand" : "Collapse"}
                </button>
              </div>
            ) : null}
          </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(pickStructuredProductInlineFilters(next));
              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(pickStructuredProductInlineFilters(defaultStructuredProductReportFilters));
              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" ? (
        <div className="min-h-0 flex-1 overflow-y-auto">
          <StructuredProductChartsPanel
            charts={charts}
            graphError={graphError}
            isGraphLoading={isGraphLoading}
          />
        </div>
      ) : (
        <>
          {structureTotals && !totalsCollapsed ? (
            <div className="flex shrink-0 flex-col gap-3">
              <NativeCurrencyTotalsStrip amountsByCurrency={structureTotals.amount} />
              <StructuredProductTotalsCards
                totalCount={totalCount}
                totals={structureTotals}
                visibleToggles={totalToggleVisibility}
              />
            </div>
          ) : null}
          <ReportLoadingPanel
            loading={isLoading}
            label="Loading structured products…"
            minHeightClassName="min-h-0"
            className={cn("flex flex-1 flex-col", isLoading && "pointer-events-none")}
          >
            {/* Plain <table>: the shared Table wrapper's overflow-x would trap the sticky header. */}
            <div className="min-h-0 flex-1 overflow-auto rounded-lg border bg-card">
              <table data-slot="table" className="w-full caption-bottom text-sm">
                <StructuredProductTableHeader
                  lifecycle={lifecycle}
                  showPotentialActions={showPotentialActions}
                  sortColumn={sortColumn}
                  sortDirection={sortDirection}
                  onSort={handleSort}
                  filters={{ ...filters, ...inlineFilters }}
                  productTypes={availableProductTypes}
                  visibleColumns={visibleColumns}
                  onFiltersChange={(next) => {
                    setInlineFilters(pickStructuredProductInlineFilters(next));
                  }}
                />
                <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={() => {
                            setDetailGroup(group);
                            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 className="max-w-xs">
                                        {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),
                                        )}
                                      >
                                        {column.field === "Underlying1" &&
                                        isPhoenixEProductRow(member) ? (
                                          <PhoenixEMemoryUnderlying
                                            row={member}
                                            pending={pendingAction !== null}
                                            onAccept={() =>
                                              void handlePotentialAction(
                                                "accept",
                                                member.underlyingMeta?.legActionId ?? null,
                                                "leg",
                                              )
                                            }
                                            onReject={() =>
                                              void handlePotentialAction(
                                                "reject",
                                                member.underlyingMeta?.legActionId ?? null,
                                                "leg",
                                              )
                                            }
                                          />
                                        ) : (
                                          <StructuredProductCell row={member} field={column.field} />
                                        )}
                                      </div>
                                    ))}
                                  </div>
                                ) : column.field === "s_isinInit" ? (
                                  <div className="flex min-w-0 items-center gap-1.5">
                                    <span className="truncate">
                                      <StructuredProductCell row={head} field={column.field} />
                                    </span>
                                    {resolvePotentialBadge({
                                      lifecycle: head.lifecycle,
                                      movePotential: head.movePotential,
                                      moveLive: head.moveLive,
                                    }) === "potential" ? (
                                      <ReportLifecycleBadge
                                        kind="potential"
                                        title={head.potentialReason}
                                      />
                                    ) : null}
                                    {resolveUpcomingBadge({ upcoming: head.upcoming }) === "upcoming" ? (
                                      <ReportLifecycleBadge
                                        kind="upcoming"
                                        title="Trade date is after today — not included in totals yet"
                                      />
                                    ) : null}
                                  </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;
                        const percent = footerConvertedPercent(column.field, structureTotals);
                        return (
                          <TableCell
                            key={`footer-${column.field}`}
                            className={cn(
                              "px-2 py-2 align-middle text-sm",
                              RIGHT_ALIGNED_FIELDS.has(column.field) && "text-right",
                            )}
                          >
                            {percent != null ? (
                              <div className="text-right tabular-nums leading-snug">
                                <span className="block text-[11px] font-normal text-muted-foreground">
                                  Total
                                </span>
                                <span
                                  className={cn(
                                    "font-semibold",
                                    percent < 0 ? "text-red-600" : "text-emerald-600",
                                  )}
                                >
                                  {percent.toFixed(2)}%
                                </span>
                              </div>
                            ) : 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 shrink-0 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>
        </>
      )}

      <StructuredProductDetailSheet
        group={detailGroup}
        open={detailOpen}
        onOpenChange={(open) => {
          setDetailOpen(open);
          if (!open) setDetailGroup(null);
        }}
      />

      <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>
  );
}
