"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 } from "next/navigation";
import { Download, RefreshCw, X } from "lucide-react";
import { toast } from "sonner";

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 { Button } from "@/components/ui/button";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Input } from "@/components/ui/input";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { DEFAULT_REPORT_PAGE_SIZE } from "@/config/pagination";
import { cn } from "@/lib/utils";

import { ReportLoadingPanel } from "@/app/customer/[tenant]/reports/_shared/components/report-loading-panel";
import {
  ReportPageNavigation,
  ReportRecordsPerPage,
  ReportSortableHead,
  ReportTableHead,
} from "@/app/customer/[tenant]/reports/_shared/components/report-table-chrome";
import { useOverallSummaryList } from "../../_lib/use-overall-summary-list";
import {
  exportOverallSummary,
  saveOverallSummaryColumnPrefsClient,
} from "../../_lib/overall-summary-api";
import { useOverallSummaryRegen } from "../../_lib/use-overall-summary-regen";
import {
  OVERALL_SUMMARY_COLUMNS,
  OVERALL_SUMMARY_LOCKED_KEYS,
  renderOverallSummaryCell,
  renderOverallSummaryFooterCell,
  resolveOverallSummaryVisibleColumns,
} from "./overall-summary-columns";
import { OverallSummaryFiltersDialog } from "./overall-summary-filters-dialog";
import { formatPlainAmount } from "@/lib/format/numbers";
import {
  type OverallSummaryColumnFilters,
  type OverallSummaryFilters,
  type OverallSummarySortKey,
  type OverallSummarySortOrder,
  defaultOverallSummaryColumnFilters,
  defaultOverallSummaryFilters,
  hasActiveOverallSummaryFilters,
} from "./schema";
import { usePortfolioScopePageReset } from "@/app/customer/_lib/admin/use-portfolio-scope-page-reset";
import {
  computeTotals,
  formatPlain,
} from "./utils";

const PAGE_SIZE_OPTIONS = [25, 50, 100, 200, 500] as const;

/** Format a backend timestamp as UTC text (stable across SSR/client timezones). */
function formatUtcTimestamp(raw: string): string | null {
  const normalized = raw.includes("T") ? raw : `${raw.replace(" ", "T")}Z`;
  const parsed = new Date(normalized);
  if (Number.isNaN(parsed.getTime())) return null;
  const pad = (n: number) => String(n).padStart(2, "0");
  return `${pad(parsed.getUTCDate())}/${pad(parsed.getUTCMonth() + 1)}/${parsed.getUTCFullYear()} ${pad(parsed.getUTCHours())}:${pad(parsed.getUTCMinutes())}`;
}

function FilterHead({
  value,
  onChange,
  placeholder,
  className,
}: {
  value: string;
  onChange: (v: string) => void;
  placeholder: string;
  className?: string;
}) {
  return (
    <TableHead className={cn("px-2 py-2", className)}>
      <Input
        value={value}
        onChange={(e) => onChange(e.target.value)}
        placeholder={placeholder}
        className="h-8 min-w-28 text-xs"
      />
    </TableHead>
  );
}

function PortfolioTotalsBar({
  currencyTotals,
  portfolioValue,
  reportingCurrency,
  excludeCount,
  lastUpdated,
}: {
  currencyTotals: { currency: string; total: number }[];
  portfolioValue: number;
  reportingCurrency: string;
  excludeCount: number;
  lastUpdated: string | null;
}) {
  // Banner shows the FX-converted AUM total from the backend — never recalculate from rows.
  const currency =
    currencyTotals[0]?.currency || reportingCurrency || "USD";
  const total = Number.isFinite(portfolioValue) ? portfolioValue : 0;

  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 market value
        </span>
        <p 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">
            {formatPlain(total, 2)}
          </span>
        </p>
        {excludeCount > 0 ? (
          <span className="shrink-0 text-[10px] text-amber-600 dark:text-amber-400">
            *excluding {excludeCount} transactions
          </span>
        ) : null}
        {lastUpdated ? (
          <span className="ml-auto shrink-0 whitespace-nowrap text-muted-foreground text-[11px]">
            Updated {lastUpdated} UTC
          </span>
        ) : null}
      </div>
    </div>
  );
}

export function OverallSummaryView() {
  const params = useParams<{ tenant?: string }>();
  const tenant = typeof params?.tenant === "string" && params.tenant.trim() ? params.tenant.trim() : resolveCustomerTenant();
  const [filters, setFilters] = React.useState<OverallSummaryFilters>(defaultOverallSummaryFilters);
  const [columnFilters, setColumnFilters] = React.useState<OverallSummaryColumnFilters>(
    defaultOverallSummaryColumnFilters,
  );
  const [sortKey, setSortKey] = React.useState<OverallSummarySortKey | null>("refId");
  const [sortOrder, setSortOrder] = React.useState<OverallSummarySortOrder>("desc");
  const [page, setPage] = React.useState(0);
  const [pageSize, setPageSize] = React.useState<number>(DEFAULT_REPORT_PAGE_SIZE);
  const [refreshKey, setRefreshKey] = React.useState(0);

  // Portfolio Scope Apply / banner Clear: also drop page search
  // filters via the shared reset hook (same contract as structure/accumulator).
  usePortfolioScopePageReset(
    React.useCallback(() => {
      setFilters(defaultOverallSummaryFilters);
      setColumnFilters(defaultOverallSummaryColumnFilters);
      setPage(0);
      setRefreshKey((value) => value + 1);
    }, []),
  );

  const [isExporting, setIsExporting] = React.useState(false);
  const [fieldsOpen, setFieldsOpen] = React.useState(false);

  const handleRegenCompleted = React.useCallback(() => {
    // Rebuild finished — bump refreshKey so the next list fetch also hits /totals.
    setRefreshKey((k) => k + 1);
    toast.success("Overall summary rebuilt");
  }, []);

  const handleRegenFailed = React.useCallback((error: string) => {
    toast.error(error);
  }, []);

  const {
    state: regenState,
    isBusy: isRebuilding,
    isStarting: isStartingRebuild,
    errorMessage: regenErrorMessage,
    startRebuild,
  } = useOverallSummaryRegen({
    onCompleted: handleRegenCompleted,
    onFailed: handleRegenFailed,
  });

  const {
    rows,
    totalCount,
    pageCount,
    reportingCurrency,
    totals,
    columnPrefs,
    empty,
    scopeActive,
    isLoading,
    errorMessage,
  } = useOverallSummaryList({
    page: page + 1,
    pageSize,
    sortKey,
    sortOrder,
    filters,
    columnFilters,
    refreshKey,
  });

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

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

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

  const pageTotals = React.useMemo(() => computeTotals(rows), [rows]);
  const currencyTotals = totals?.byCurrency?.length ? totals.byCurrency : [];

  // Banner AUM from dedicated totals endpoint (`value` = Yii1 summary_data Total Value).
  const portfolioValue =
    totals != null ? Number(totals.value) || Number(totals.marketValue) || 0 : 0;
  const headerReportingCurrency = totals?.code || reportingCurrency;
  const excludeCount = totals?.excludeCount ?? 0;
  const resolvedPageCount = Math.max(pageCount, 1);
  const pageRows = rows;
  const rangeStart = totalCount === 0 ? 0 : page * pageSize + 1;
  const rangeEnd = Math.min((page + 1) * pageSize, totalCount);

  const hasActiveFilters = hasActiveOverallSummaryFilters(filters);
  const hasColumnFilters = Object.values(columnFilters).some((v) => v.trim() !== "");
  // Rebuild only when the summary cache is truly empty — not when Scope/filters hide rows.
  // TOTAL VALUE > 0 with 0 positions means data exists; the query is just filtered.
  const portfolioTotalValue = portfolioValue;
  const isCacheEmpty =
    !isLoading && totalCount === 0 && portfolioTotalValue <= 0 && !scopeActive && !hasActiveFilters && !hasColumnFilters;
  const isFilteredEmpty = !isLoading && totalCount === 0 && !isCacheEmpty;
  const lastUpdated = React.useMemo(() => {
    const raw = regenState?.finishedAt?.trim() || regenState?.startedAt?.trim();
    if (!raw) return null;
    return formatUtcTimestamp(raw);
  }, [regenState?.finishedAt, regenState?.startedAt]);

  const handleRebuild = async () => {
    try {
      await startRebuild();
      toast.message("Rebuild queued", {
        description: "Summary table is rebuilding in the background.",
      });
    } catch (error) {
      toastApiError(error, "Could not start rebuild");
    }
  };

  const footerLabelSpan = React.useMemo(() => {
    const labelIndex = visibleColumns.findIndex((column) => column.footer === "label");
    const purchaseIndex = visibleColumns.findIndex((column) => column.footer === "purchaseValue");
    if (labelIndex < 0) return 1;
    if (purchaseIndex < 0) return Math.max(1, visibleColumns.length);
    return Math.max(1, purchaseIndex - labelIndex);
  }, [visibleColumns]);

  React.useEffect(() => {
    setPage(0);
  }, [filters, columnFilters, sortKey, sortOrder, pageSize]);

  const handleSort = (key: OverallSummarySortKey) => {
    if (sortKey === key) {
      setSortOrder((o) => (o === "asc" ? "desc" : "asc"));
    } else {
      setSortKey(key);
      setSortOrder("desc");
    }
  };

  const setCol = (key: keyof OverallSummaryColumnFilters, value: string) => {
    setColumnFilters((p) => ({ ...p, [key]: value }));
  };

  const handleExport = async (formatType: "excel" | "csv") => {
    setIsExporting(true);
    try {
      await exportOverallSummary(formatType, {
        sortKey,
        sortOrder,
        filters,
        columnFilters,
      });
      toast.success(formatType === "excel" ? "Excel download started" : "CSV download started");
    } catch (error) {
      toastApiError(error, "Export failed");
    } finally {
      setIsExporting(false);
    }
  };

  const meta = {
    title: "Overall Summary",
    reportingCurrency: headerReportingCurrency,
  };

  const emptyTableMessage = (() => {
    if (isLoading || isRebuilding) return "";
    if (isCacheEmpty) {
      return "Summary table is empty. Rebuild to refresh holdings from live data.";
    }
    if (scopeActive) {
      return "No holdings for the current Portfolio Scope. Clear Scope or pick another User/Customer.";
    }
    return "No holdings match your filters.";
  })();
  const showLoadingOverlay = isLoading || isRebuilding;

  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="shrink-0">
          <h1 className="font-semibold text-2xl tracking-tight">{meta.title}</h1>
          <p className="text-muted-foreground text-sm">
            Displaying {rangeStart}-{rangeEnd} of {formatPlainAmount(totalCount)} results.
            {isLoading ? " Loading…" : ""}
            {isRebuilding
              ? regenState?.regenStatus === "queued"
                ? " Rebuild queued…"
                : " Rebuilding…"
              : ""}
          </p>
          {errorMessage ? <p className="text-destructive text-sm">{errorMessage}</p> : null}
          {regenErrorMessage ? <p className="text-destructive text-sm">{regenErrorMessage}</p> : null}
          {regenState?.regenStatus === "failed" && !isRebuilding ? (
            <p className="text-destructive text-sm">Rebuild failed</p>
          ) : null}
        </div>

        <div className="flex w-full min-w-0 flex-wrap items-center justify-end gap-2 sm:ml-auto sm:w-auto">
          <ReportRecordsPerPage
            id="overall-summary-rows-per-page"
            pageSize={pageSize}
            options={PAGE_SIZE_OPTIONS}
            onPageSizeChange={(size) => {
              setPageSize(size);
              setPage(0);
            }}
          />
          <OverallSummaryFiltersDialog filters={filters} onApply={setFilters} />
          <CustomerFieldsButton onClick={() => setFieldsOpen(true)} />
          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <Button variant="outline" size="icon-lg" className="h-9 w-9 shrink-0">
                <Download className="size-4" />
                <span className="sr-only">Download</span>
              </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent align="end">
              <DropdownMenuItem
                disabled={isExporting || isLoading || isRebuilding}
                onClick={() => void handleExport("excel")}
              >
                Download Excel
              </DropdownMenuItem>
              <DropdownMenuItem
                disabled={isExporting || isLoading || isRebuilding}
                onClick={() => void handleExport("csv")}
              >
                Download CSV
              </DropdownMenuItem>
            </DropdownMenuContent>
          </DropdownMenu>
          <Button
            variant="outline"
            size="icon-lg"
            className="h-9 w-9 shrink-0"
            disabled={isLoading}
            onClick={() => {
              setRefreshKey((k) => k + 1);
              toast.success("Summary list refreshed");
            }}
            title="Reload list"
          >
            <RefreshCw className={cn("size-4", isLoading && "animate-spin")} />
            <span className="sr-only">Reload list</span>
          </Button>
          <Button
            variant={empty ? "default" : "outline"}
            size="sm"
            className="h-9 shrink-0 gap-1.5"
            disabled={isRebuilding || isStartingRebuild}
            onClick={() => void handleRebuild()}
          >
            <RefreshCw className={cn("size-3.5", isRebuilding && "animate-spin")} />
            {isRebuilding ? "Rebuilding…" : "Rebuild"}
          </Button>
          <Button variant="outline" size="icon-lg" className="h-9 w-9 shrink-0" asChild>
            <Link href={`/customer/${tenant}/dashboard`}>
              <X className="size-4" />
              <span className="sr-only">Close</span>
            </Link>
          </Button>
        </div>
      </div>

      {isCacheEmpty && !isRebuilding ? (
        <div className="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-dashed bg-muted/30 px-4 py-3">
          <p className="text-muted-foreground text-sm">
            No cached summary rows for this tenant. Rebuild from live holdings to populate the report.
          </p>
          <Button size="sm" disabled={isStartingRebuild} onClick={() => void handleRebuild()}>
            Rebuild summary
          </Button>
        </div>
      ) : null}
      {isFilteredEmpty && scopeActive && !isRebuilding ? (
        <div className="flex flex-wrap items-center justify-between gap-3 rounded-lg border px-4 py-3">
          <p className="text-muted-foreground text-sm">
            Portfolio Scope is active and this selection has no Overall Summary rows. Clear Scope, or
            rebuild after confirming live Transactions exist for that customer.
          </p>
        </div>
      ) : null}

      <PortfolioTotalsBar
        currencyTotals={currencyTotals}
        portfolioValue={portfolioValue}
        reportingCurrency={headerReportingCurrency}
        excludeCount={excludeCount}
        lastUpdated={lastUpdated}
      />

      <ReportLoadingPanel
        loading={showLoadingOverlay}
        label={isRebuilding ? "Rebuilding summary table…" : "Loading holdings…"}
        className={cn(showLoadingOverlay && "pointer-events-none")}
      >
        <div className="overflow-x-auto rounded-lg border bg-card">
          <Table>
            <TableHeader>
              <TableRow className="bg-muted/20 hover:bg-muted/20">
                {visibleColumns.map((column) => {
                  const headClass = cn(
                    column.align === "right" && "text-right",
                    column.headClassName,
                  );
                  if (column.sortKey) {
                    return (
                      <ReportSortableHead
                        key={column.key}
                        label={column.label}
                        onSort={() => handleSort(column.sortKey!)}
                        className={headClass}
                        align={column.align === "right" ? "right" : "left"}
                      />
                    );
                  }
                  return (
                    <ReportTableHead key={column.key} className={headClass}>
                      {column.label}
                    </ReportTableHead>
                  );
                })}
              </TableRow>
              <TableRow className="bg-muted/10 hover:bg-muted/10">
                {visibleColumns.map((column) => {
                  if (column.filterKey) {
                    return (
                      <FilterHead
                        key={column.key}
                        value={columnFilters[column.filterKey]}
                        onChange={(v) => setCol(column.filterKey!, v)}
                        placeholder={column.filterPlaceholder || column.label}
                        className={column.headClassName}
                      />
                    );
                  }
                  return <TableHead key={column.key} className="px-2 py-2" />;
                })}
              </TableRow>
            </TableHeader>
            <TableBody>
              {pageRows.length === 0 && !showLoadingOverlay ? (
                <TableRow>
                  <TableCell
                    colSpan={Math.max(visibleColumns.length, 1)}
                    className="h-24 text-center text-muted-foreground text-sm"
                  >
                    <div className="flex flex-col items-center gap-3">
                      <span>{emptyTableMessage}</span>
                      {isCacheEmpty && !isRebuilding ? (
                        <Button size="sm" onClick={() => void handleRebuild()}>
                          Rebuild summary
                        </Button>
                      ) : null}
                    </div>
                  </TableCell>
                </TableRow>
              ) : (
                pageRows.map((row, index) => (
                  <TableRow key={row.id} className={index % 2 === 0 ? "bg-muted/5" : undefined}>
                    {visibleColumns.map((column) => (
                      <TableCell
                        key={column.key}
                        className={cn(
                          "px-2 py-2 align-middle text-sm",
                          column.align === "right" && "text-right tabular-nums",
                          column.key === "refId" || column.key === "isin"
                            ? "whitespace-nowrap font-mono"
                            : column.key === "parentBank"
                              ? "whitespace-nowrap text-muted-foreground"
                              : column.key === "remarks"
                                ? "text-muted-foreground"
                                : "whitespace-nowrap",
                          column.cellClassName,
                        )}
                      >
                        {renderOverallSummaryCell(column, row)}
                      </TableCell>
                    ))}
                  </TableRow>
                ))
              )}
            </TableBody>
            {pageRows.length > 0 ? (
              <tfoot>
                <TableRow className="border-t-2 bg-muted/40 font-semibold hover:bg-muted/40">
                  {(() => {
                    const cells: React.ReactNode[] = [];
                    let skipUntil = -1;
                    visibleColumns.forEach((column, index) => {
                      if (index < skipUntil) return;
                      const rendered = renderOverallSummaryFooterCell(column, pageTotals, footerLabelSpan);
                      if (!rendered) return;
                      const colSpan = rendered.colSpan ?? 1;
                      if (colSpan > 1) skipUntil = index + colSpan;
                      cells.push(
                        <TableCell key={column.key} colSpan={colSpan} className={cn("px-2 py-2", rendered.className)}>
                          {rendered.content}
                        </TableCell>,
                      );
                    });
                    return cells;
                  })()}
                </TableRow>
              </tfoot>
            ) : null}
          </Table>
        </div>
      </ReportLoadingPanel>

      {totalCount > 0 ? (
        <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
          <p className="text-muted-foreground text-sm">
            Page {resolvedPageCount === 0 ? 0 : page + 1} of {resolvedPageCount}
          </p>
          <ReportPageNavigation
            page={page + 1}
            pageCount={resolvedPageCount}
            onPageChange={(next) => setPage(next - 1)}
            disabled={isLoading || isRebuilding}
          />
        </div>
      ) : null}

      <CustomerFieldsPanel
        open={fieldsOpen}
        onOpenChange={setFieldsOpen}
        catalog={OVERALL_SUMMARY_COLUMNS}
        visibility={columnVisibility as Record<string, boolean>}
        order={columnOrder}
        lockedKeys={OVERALL_SUMMARY_LOCKED_KEYS}
        title="Fields"
        description="Choose which columns to show in the overall summary table and drag to reorder."
        onToggle={setColumnVisible}
        onReorder={reorderShown}
        onHideAll={hideAll}
      />
    </div>
  );
}
