import type { ColumnDef } from "@tanstack/react-table";

import { labelForGridColumn, type CustomerGridColumn } from "@/app/customer/_lib/customer-grid-columns";
import { CustomerSortableHeader } from "@/components/customer/customer-table-primitives";
import { formatApiDate } from "@/lib/format/dates";

/**
 * Builders for the column definitions every customer asset list repeats.
 *
 * Each `columns.tsx` used to spell these out by hand, so `uid_title`,
 * `placement_date` and `bank` were re-typed in 17 files and the blank-value
 * helper existed as 25 identical private copies under two different names
 * (`displayCell` / `displayBank`).
 *
 * Module-specific columns stay hand-written: amount, quantity and price genuinely
 * differ per module (labels, sign colouring, formatter, empty handling), and
 * forcing them through a builder would cost more in options than it saves.
 */

export const EM_DASH = "—";

/** Blank-safe cell text: renders an em dash instead of an empty cell. */
export function displayCell(value: string | null | undefined): string {
  return value?.trim() ? value : EM_DASH;
}

export type AssetColumnContext = {
  gridColumns: CustomerGridColumn[] | undefined;
};

type AssetColumnConfig<TRow> = {
  /** Grid column id; also the key used to look up the tenant's custom label. */
  id: string;
  accessorKey: string;
  /** Fallback header label when the tenant has not renamed the column. */
  label: string;
  read: (row: TRow) => string;
  className?: string;
  /**
   * Render `EM_DASH` for blank values.
   *
   * Deliberately opt-in: modules currently disagree about this for the same
   * column (e.g. `currency` dashes in 6 modules and renders blank in 7), so the
   * default must not silently change any existing page.
   */
  blankAsDash?: boolean;
};

function headerFor(gridColumns: CustomerGridColumn[] | undefined, id: string, label: string) {
  return function Header({ column }: { column: Parameters<typeof CustomerSortableHeader>[0]["column"] }) {
    return <CustomerSortableHeader label={labelForGridColumn(gridColumns, id, label)} column={column} />;
  };
}

/** Sortable text column. */
export function assetTextColumn<TRow>(
  { gridColumns }: AssetColumnContext,
  {
    id,
    accessorKey,
    label,
    read,
    className = "text-sm",
    blankAsDash = false,
  }: AssetColumnConfig<TRow>,
): ColumnDef<TRow> {
  return {
    id,
    accessorKey,
    header: headerFor(gridColumns, id, label),
    cell: ({ row }) => {
      const value = read(row.original);
      return <span className={className}>{blankAsDash ? displayCell(value) : value}</span>;
    },
  } as ColumnDef<TRow>;
}

/** Sortable date column rendered as `dd MMM yyyy`, falling back to the raw API value. */
export function assetDateColumn<TRow>(
  { gridColumns }: AssetColumnContext,
  {
    id,
    accessorKey,
    label,
    read,
    className = "whitespace-nowrap text-sm",
    blankAsDash = false,
  }: AssetColumnConfig<TRow>,
): ColumnDef<TRow> {
  return {
    id,
    accessorKey,
    header: headerFor(gridColumns, id, label),
    cell: ({ row }) => {
      const raw = read(row.original);
      const formatted = formatApiDate(raw, "dd MMM yyyy", raw);
      return <span className={className}>{blankAsDash ? displayCell(formatted) : formatted}</span>;
    },
  } as ColumnDef<TRow>;
}

/** Row shape the standard lead columns read from. */
export type StandardAssetLeadRow = {
  refId: string;
  placementDate: string;
  bank: string;
};

/**
 * The `Ref. ID` / `Placement Date` / `Bank` triple that opens most asset lists.
 *
 * Modules that interpose another column (fixed-deposit, swaps, cash-withdrawal)
 * or reorder the pair (fx-accumulator) should compose `assetTextColumn` and
 * `assetDateColumn` directly instead.
 */
export function standardAssetLeadColumns<TRow extends StandardAssetLeadRow>(
  ctx: AssetColumnContext,
): ColumnDef<TRow>[] {
  return [
    assetTextColumn<TRow>(ctx, {
      id: "uid_title",
      accessorKey: "refId",
      label: "Ref. ID",
      read: (row) => row.refId,
      className: "whitespace-nowrap text-sm",
    }),
    assetDateColumn<TRow>(ctx, {
      id: "placement_date",
      accessorKey: "placementDate",
      label: "Placement Date",
      read: (row) => row.placementDate,
    }),
    assetTextColumn<TRow>(ctx, {
      id: "bank",
      accessorKey: "bank",
      label: "Bank",
      read: (row) => row.bank,
      blankAsDash: true,
    }),
  ];
}
