"use client";

import { toastApiError } from "@/lib/toast-api-error";
import * as React from "react";

import {
  type ColumnDef,
  flexRender,
  getCoreRowModel,
  type PaginationState,
  type SortingState,
  useReactTable,
} from "@tanstack/react-table";
import { RefreshCw } from "lucide-react";
import type { DateRange } from "react-day-picker";
import {
  CustomerFieldsButton,
  CustomerFieldsPanel,
} from "@/app/customer/_components/customer-fields-panel";
import { useCustomerPortalSession } from "@/app/customer/_components/customer-portal-session-context";
import type { CustomerTransactionModuleId } from "@/app/customer/_lib/customer-asset-modules";
import {
  type CustomerColumnPrefs,
  type CustomerGridColumn,
} from "@/app/customer/_lib/customer-grid-columns";
import { useCustomerTableColumnPrefs } from "@/app/customer/_lib/use-customer-table-column-prefs";
import { useCustomerTransactionDelete } from "@/app/customer/_lib/use-customer-transaction-delete";
import {
  NewTransactionButton,
  useTransactionFormEdit,
} from "@/components/form/transaction-workspace/list-table-form-actions";
import type { TransactionModuleFormConfig } from "@/components/form/transaction-workspace/types";
import { ErrorBanner } from "@/components/shared/error-banner";
import { Button } from "@/components/ui/button";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";

import type { TransactionTableRow } from "./customer-transaction-list-columns";
import {
  CustomerTransactionListFilterRow,
  renderCustomerAssetColumnFilter,
  type TransactionFilterOptions,
  type TransactionRangeFilters,
} from "./customer-transaction-list-filters";
import { CustomerTablePageNavigation, CustomerTableRecordsPerPage } from "./customer-table-pagination";
import { formatPlainAmount } from "@/lib/format/numbers";

export type TransactionDetailSheetProps<TRow> = {
  row: TRow | null;
  open: boolean;
  onOpenChange: (open: boolean) => void;
  onEdit: (row: TRow) => void;
  onDelete: (row: TRow) => void;
};

export type CustomerAssetServerListState<TRow> = {
  rows: TRow[];
  setRows: React.Dispatch<React.SetStateAction<TRow[]>>;
  totalCount: number;
  pageCount: number;
  isLoading: boolean;
  errorMessage: string | null;
  refresh: () => void;
  onRefreshClick?: () => void;
  canCreate: boolean;
  pagination: PaginationState;
  setPagination: React.Dispatch<React.SetStateAction<PaginationState>>;
  sorting: SortingState;
  setSorting: React.Dispatch<React.SetStateAction<SortingState>>;
  getFilterValue: (columnId: string) => string;
  onColumnFilterChange: (columnId: string, value: string | undefined) => void;
  placementDateRange: DateRange | undefined;
  onPlacementDateRangeChange: (range: DateRange | undefined) => void;
  filterOptions: TransactionFilterOptions;
  rangeFilters?: TransactionRangeFilters;
  onRangeFilterChange?: (
    field: keyof TransactionRangeFilters,
    value: { from?: string; to?: string },
  ) => void;
  showParentIsinFilter?: boolean;
  /** When false, hides the shared transaction filter row (e.g. cash-balance grid). */
  showFilterRow?: boolean;
};

export type CustomerAssetColumnPrefsConfig = {
  catalog: CustomerGridColumn[];
  initialPrefs: CustomerColumnPrefs | null;
  savePrefs: (prefs: CustomerColumnPrefs) => Promise<void>;
  lockedKeys?: string[];
};

type CustomerAssetServerListTableProps<TRow extends TransactionTableRow> = {
  title: string;
  emptyMessage: string;
  rowsPerPageId: string;
  moduleId?: CustomerTransactionModuleId;
  /** When set, picks the delete/update module per row (Deposit hub: Dc vs Cl). */
  resolveModuleId?: (row: TRow) => CustomerTransactionModuleId | null;
  /** When set, overrides formConfig.listPath for Edit navigation per row. */
  resolveEditListPath?: (row: TRow) => string | null;
  singularName: string;
  formConfig?: Pick<TransactionModuleFormConfig, "listPath" | "newButtonLabel">;
  editMode?: "form" | "placeholder";
  columnFactory: (handlers: {
    onView: (row: TRow) => void;
    onEdit: (row: TRow) => void;
  }) => ColumnDef<TRow>[];
  DetailSheet: React.ComponentType<TransactionDetailSheetProps<TRow>>;
  server: CustomerAssetServerListState<TRow>;
  /** Optional extra actions rendered in the toolbar, before the New button. */
  toolbarActions?: React.ReactNode;
  /** When false, hides the generic New transaction button (stock funds uses a custom create menu). */
  showNewButton?: boolean;
  /**
   * Optional custom filter row. When provided, replaces the shared stock-style
   * transaction filter row (used by cash-balance and similar grids).
   */
  filterRow?: React.ReactNode;
  /** When set, enables Fields panel + per-user column visibility/order. */
  columnPrefs?: CustomerAssetColumnPrefsConfig;
};

export function CustomerAssetServerListTable<TRow extends TransactionTableRow>({
  title,
  emptyMessage,
  rowsPerPageId,
  moduleId,
  resolveModuleId,
  resolveEditListPath,
  singularName,
  formConfig,
  editMode = formConfig ? "form" : "placeholder",
  columnFactory,
  DetailSheet,
  server,
  toolbarActions,
  showNewButton = true,
  filterRow,
  columnPrefs,
}: CustomerAssetServerListTableProps<TRow>) {
  const { canCreateTransactions } = useCustomerPortalSession();
  const [selectedRow, setSelectedRow] = React.useState<TRow | null>(null);
  const [detailOpen, setDetailOpen] = React.useState(false);
  const [fieldsOpen, setFieldsOpen] = React.useState(false);

  const handleView = React.useCallback((row: TRow) => {
    setSelectedRow(row);
    setDetailOpen(true);
  }, []);

  const navigateToEdit = useTransactionFormEdit(formConfig ?? { listPath: "" });

  const handleEdit = React.useCallback(
    (row: TRow) => {
      if (editMode !== "form") {
        return;
      }

      const closeDetail = () => {
        setDetailOpen(false);
        setSelectedRow(null);
      };

      const editListPath = resolveEditListPath?.(row);
      if (editListPath) {
        navigateToEdit(
          row,
          closeDetail,
          // Prefer per-row form module path (Deposit hub Dc/Cl).
          editListPath,
        );
        return;
      }

      if (formConfig) {
        navigateToEdit(row, closeDetail);
      }
    },
    [editMode, formConfig, navigateToEdit, resolveEditListPath],
  );

  const { deleteRow: handleDelete } = useCustomerTransactionDelete<TRow>({
    moduleId,
    resolveModuleId,
    singularName,
    onDeleted: (row) => {
      server.setRows((prev) => prev.filter((item) => item.id !== row.id));
      setDetailOpen(false);
      setSelectedRow(null);
    },
  });

  const columns = React.useMemo(
    () => columnFactory({ onView: handleView, onEdit: handleEdit }),
    [columnFactory, handleEdit, handleView],
  );

  const lockedKeys = columnPrefs?.lockedKeys ?? ["options"];
  const savePrefs = React.useCallback(
    async (prefs: CustomerColumnPrefs) => {
      if (!columnPrefs) return;
      try {
        await columnPrefs.savePrefs(prefs);
      } catch (error) {
        toastApiError(error, "Failed to save column preferences.");
        throw error;
      }
    },
    [columnPrefs],
  );

  const {
    columnVisibility,
    columnOrder,
    onColumnVisibilityChange,
    onColumnOrderChange,
    hideAll,
    setColumnVisible,
    reorderShown,
  } = useCustomerTableColumnPrefs({
    catalog: columnPrefs?.catalog ?? [],
    initialPrefs: columnPrefs?.initialPrefs ?? null,
    lockedKeys,
    savePrefs,
  });

  const table = useReactTable({
    data: server.rows,
    columns,
    rowCount: server.totalCount,
    pageCount: server.pageCount || undefined,
    manualPagination: true,
    manualSorting: true,
    autoResetPageIndex: false,
    state: {
      sorting: server.sorting,
      pagination: server.pagination,
      ...(columnPrefs
        ? {
            columnVisibility,
            columnOrder,
          }
        : {}),
    },
    onSortingChange: (updater) => {
      server.setSorting(updater);
      server.setPagination((current) => ({ ...current, pageIndex: 0 }));
    },
    onPaginationChange: server.setPagination,
    ...(columnPrefs
      ? {
          onColumnVisibilityChange,
          onColumnOrderChange,
        }
      : {}),
    getCoreRowModel: getCoreRowModel(),
  });

  const { pageIndex, pageSize } = table.getState().pagination;
  const start = server.totalCount === 0 ? 0 : pageIndex * pageSize + 1;
  const end = Math.min((pageIndex + 1) * pageSize, server.totalCount);
  const visibleLeafColumns = table.getVisibleLeafColumns();
  const useDynamicFilters = Boolean(columnPrefs) && filterRow === undefined && server.showFilterRow !== false;

  return (
    <div className="flex min-w-0 flex-col gap-4">
      <ErrorBanner message={server.errorMessage} className="mb-0" />

      <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">{title}</h1>
          <p className="text-muted-foreground text-sm">
            Displaying {start}-{end} of {formatPlainAmount(server.totalCount)} results.
          </p>
        </div>

        <div className="flex w-full shrink-0 flex-wrap items-center justify-end gap-2 sm:ml-auto sm:w-auto">
          <CustomerTableRecordsPerPage table={table} rowsPerPageId={rowsPerPageId} />
          {toolbarActions}
          {columnPrefs ? <CustomerFieldsButton onClick={() => setFieldsOpen(true)} /> : null}
          {formConfig && canCreateTransactions && showNewButton ? (
            <NewTransactionButton config={formConfig} />
          ) : null}
          <Button
            variant="outline"
            size="icon-lg"
            className="h-9 w-9 shrink-0"
            onClick={() => (server.onRefreshClick ?? server.refresh)()}
            disabled={server.isLoading}
          >
            <RefreshCw className="size-4" />
            <span className="sr-only">Refresh</span>
          </Button>
        </div>
      </div>

      <div className="overflow-x-auto rounded-lg border bg-card">
        <Table>
          <TableHeader>
            <TableRow className="bg-muted/20 hover:bg-muted/20">
              {table.getHeaderGroups()[0]?.headers.map((header) => (
                <TableHead key={header.id} className="h-10 whitespace-nowrap px-2">
                  {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
                </TableHead>
              ))}
            </TableRow>
            {filterRow !== undefined ? (
              filterRow
            ) : server.showFilterRow === false ? null : useDynamicFilters ? (
              <TableRow className="bg-muted/10 hover:bg-muted/10">
                {visibleLeafColumns.map((column) => (
                  <TableHead key={`filter-${column.id}`} className="px-2 py-2">
                    {renderCustomerAssetColumnFilter({
                      columnId: column.id,
                      table,
                      filterOptions: server.filterOptions,
                      placementDateRange: server.placementDateRange,
                      onPlacementDateRangeChange: server.onPlacementDateRangeChange,
                      onColumnFilterChange: (columnId, value) => {
                        server.onColumnFilterChange(columnId, value);
                        server.setPagination((current) => ({ ...current, pageIndex: 0 }));
                      },
                      getFilterValue: server.getFilterValue,
                      serverMode: true,
                      rangeFilters: server.rangeFilters,
                      onRangeFilterChange: server.onRangeFilterChange,
                    })}
                  </TableHead>
                ))}
              </TableRow>
            ) : (
              <CustomerTransactionListFilterRow
                table={table}
                filterOptions={server.filterOptions}
                placementDateRange={server.placementDateRange}
                onPlacementDateRangeChange={server.onPlacementDateRangeChange}
                onColumnFilterChange={(columnId, value) => {
                  server.onColumnFilterChange(columnId, value);
                  server.setPagination((current) => ({ ...current, pageIndex: 0 }));
                }}
                getFilterValue={server.getFilterValue}
                serverMode
                rangeFilters={server.rangeFilters}
                onRangeFilterChange={server.onRangeFilterChange}
                showParentIsinFilter={server.showParentIsinFilter}
              />
            )}
          </TableHeader>
          <TableBody>
            {server.isLoading ? (
              <TableRow>
                <TableCell
                  colSpan={Math.max(visibleLeafColumns.length, 1)}
                  className="h-24 text-center text-muted-foreground text-sm"
                >
                  Loading...
                </TableCell>
              </TableRow>
            ) : table.getRowModel().rows.length ? (
              table.getRowModel().rows.map((row, index) => (
                <TableRow key={row.id} className={index % 2 === 0 ? "bg-muted/5" : undefined}>
                  {row.getVisibleCells().map((cell) => (
                    <TableCell key={cell.id} className="px-2 py-2 align-middle">
                      {flexRender(cell.column.columnDef.cell, cell.getContext())}
                    </TableCell>
                  ))}
                </TableRow>
              ))
            ) : (
              <TableRow>
                <TableCell colSpan={Math.max(visibleLeafColumns.length, 1)} className="h-24 text-center">
                  {emptyMessage}
                </TableCell>
              </TableRow>
            )}
          </TableBody>
        </Table>
      </div>

      <div className="mt-4 border-t pt-4">
        <CustomerTablePageNavigation table={table} />
      </div>

      <DetailSheet
        row={selectedRow}
        open={detailOpen}
        onOpenChange={(open) => {
          setDetailOpen(open);
          if (!open) setSelectedRow(null);
        }}
        onEdit={handleEdit}
        onDelete={handleDelete}
      />

      {columnPrefs ? (
        <CustomerFieldsPanel
          open={fieldsOpen}
          onOpenChange={setFieldsOpen}
          catalog={columnPrefs.catalog}
          visibility={columnVisibility as Record<string, boolean>}
          order={columnOrder}
          lockedKeys={lockedKeys}
          onToggle={setColumnVisible}
          onReorder={reorderShown}
          onHideAll={hideAll}
        />
      ) : null}
    </div>
  );
}
