"use client"

import * as React from "react"
import { X } from "lucide-react"

import { ReportLifecycleBadge } from "@/app/customer/[tenant]/reports/_shared/components/report-lifecycle-badge"
import { Input } from "@/components/ui/input"
import { cn } from "@/lib/utils"

import {
  PIB_PIVOT_ASSET_COLUMNS,
  PIB_PIVOT_LOAN_BUCKET,
  pivotAssetTotal,
  pivotBankMissingCount,
  pivotBankMissingValue,
  pivotInferredValue,
  pivotPotentialCount,
  pivotPotentialValue,
  pivotUnmappedCount,
  type PibPivotAssetBucketKey,
  type PibPivotBucketKey,
  type PibPivotRow,
} from "../_lib/pib-pivot-data"
import {
  EMPTY_PIVOT_COLUMN_FILTERS,
  PIVOT_FLAG_KEYS,
  PIVOT_STICKY_COLS,
  buildCustomerGroupMeta,
  filterPivotRows,
  formatPibValue,
  hasActivePivotColumnFilters,
  isDrillableAmount,
  pivotAmountCellTitles,
  pivotDimValues,
  pivotHasMeta,
  pivotTrailingColumnCount,
  stickyLeft,
  sumPivotColumnTotals,
  type PivotColumnFilters,
  type PivotDimKey,
  type PivotMeta,
} from "../_lib/pib-pivot-sheet"
import type { PibPivotDetailTarget } from "./pib-pivot-detail-dialog"

/** Keep amount columns from collapsing so whitespace-nowrap values do not bleed left. */
const PIVOT_AMOUNT_COL_MIN_WIDTH = 108
const AMOUNT_COL_STYLE = { minWidth: PIVOT_AMOUNT_COL_MIN_WIDTH, width: PIVOT_AMOUNT_COL_MIN_WIDTH }

/** Must match rendered label-header row height (incl. B410 code line). */
const PIVOT_LABEL_HEADER_HEIGHT = 40
const PIVOT_FILTER_HEADER_TOP = PIVOT_LABEL_HEADER_HEIGHT

const CELL_PAD = "px-2 py-1.5"
const STICKY_EDGE_SHADOW = "border-r shadow-[2px_0_4px_-2px_rgba(0,0,0,0.12)]"
const STICKY_HEADER_EDGE_SHADOW = "border-r shadow-[2px_0_4px_-2px_rgba(0,0,0,0.15)]"
const TOTALS_AMOUNT_CELL = "sticky bottom-0 z-20 bg-muted text-right font-semibold tabular-nums whitespace-nowrap"

function aumClass(value: number | null | undefined): string {
  if (value == null) return "text-muted-foreground/40"
  if (value < 0) return "text-red-600 dark:text-red-400"
  if (value === 0) return "text-muted-foreground/50"
  return "tabular-nums text-foreground"
}

/** Position + fixed width of pinned column `index`; callers add their own top / bottom. */
function stickyColStyle(index: number) {
  const width = PIVOT_STICKY_COLS[index].width
  return { left: stickyLeft(index), width, minWidth: width, maxWidth: width }
}

function isLastStickyCol(index: number): boolean {
  return index === PIVOT_STICKY_COLS.length - 1
}

type OpenDetail = (row: PibPivotRow, bucket: PibPivotBucketKey, bucketLabel: string, cellValue: number) => void

export function PivotSheet({
  rows,
  onCellClick,
  onFilterStatsChange,
}: {
  rows: PibPivotRow[]
  onCellClick?: (target: PibPivotDetailTarget) => void
  onFilterStatsChange?: (stats: { visible: number; total: number; active: boolean }) => void
}) {
  const [columnFilters, setColumnFilters] = React.useState<PivotColumnFilters>(EMPTY_PIVOT_COLUMN_FILTERS)
  const visibleRows = React.useMemo(
    () => filterPivotRows(rows, columnFilters),
    [rows, columnFilters]
  )
  const columnTotals = React.useMemo(() => sumPivotColumnTotals(visibleRows), [visibleRows])
  const customerGroups = React.useMemo(
    () => buildCustomerGroupMeta(visibleRows),
    [visibleRows]
  )
  const filtersActive = hasActivePivotColumnFilters(columnFilters)
  const meta = pivotHasMeta(rows)
  const trailingColumnCount = pivotTrailingColumnCount(meta)

  React.useEffect(() => {
    onFilterStatsChange?.({
      visible: visibleRows.length,
      total: rows.length,
      active: filtersActive,
    })
  }, [visibleRows.length, rows.length, filtersActive, onFilterStatsChange])

  const openDetail: OpenDetail = (row, bucket, bucketLabel, cellValue) => {
    const customerId = row.customerId ?? 0
    if (!onCellClick || customerId <= 0 || row.bank.trim() === "") {
      return
    }
    onCellClick({
      bucket,
      bucketLabel,
      customerId,
      bank: row.bank,
      client: row.client,
      cellValue,
    })
  }

  return (
    <div className="min-h-0 flex-1 overflow-auto">
      <table className="w-max min-w-full caption-bottom border-collapse text-sm leading-snug">
        <PivotSheetHead
          meta={meta}
          trailingColumnCount={trailingColumnCount}
          columnFilters={columnFilters}
          onFilterChange={(key, value) => setColumnFilters((prev) => ({ ...prev, [key]: value }))}
          onClearFilters={() => setColumnFilters(EMPTY_PIVOT_COLUMN_FILTERS)}
          filtersActive={filtersActive}
          visibleCount={visibleRows.length}
          totalCount={rows.length}
        />
        <tbody>
          {visibleRows.length === 0 ? (
            <tr>
              <td
                colSpan={PIVOT_STICKY_COLS.length + trailingColumnCount}
                className="px-4 py-8 text-center text-muted-foreground text-xs"
              >
                {filtersActive ? "No pivot rows match these column filters." : "No pivot data."}
              </td>
            </tr>
          ) : (
            visibleRows.map((row, rowIndex) => (
              <PivotSheetRow
                key={`${row.customerId ?? "x"}-${row.bank}-${row.client}-${row.rm}-${rowIndex}`}
                row={row}
                meta={meta}
                groupSize={customerGroups.size[rowIndex] ?? 1}
                groupIndex={customerGroups.indexInGroup[rowIndex] ?? 0}
                onDrill={onCellClick ? openDetail : undefined}
              />
            ))
          )}
        </tbody>
        {visibleRows.length > 0 ? <PivotSheetTotals meta={meta} totals={columnTotals} /> : null}
      </table>
    </div>
  )
}

function PivotHeaderCell({
  code,
  label,
  className,
}: {
  code?: string
  label: string
  className?: string
}) {
  return (
    <th
      title={code ? `${code} — ${label}` : label}
      style={{
        top: 0,
        height: PIVOT_LABEL_HEADER_HEIGHT,
        ...AMOUNT_COL_STYLE,
      }}
      className={cn(
        "sticky top-0 z-10 border-b bg-muted px-2 py-0 align-bottom font-medium text-xs whitespace-nowrap text-foreground",
        className
      )}
    >
      <div className="flex h-full flex-col justify-end gap-0.5 pb-1">
        <span className="leading-tight">{label}</span>
        {code ? (
          <span className="font-normal font-mono text-[10px] leading-none text-muted-foreground">
            {code}
          </span>
        ) : (
          <span className="h-2.5" aria-hidden />
        )}
      </div>
    </th>
  )
}

/** Label row + filter row. */
function PivotSheetHead({
  meta,
  trailingColumnCount,
  columnFilters,
  onFilterChange,
  onClearFilters,
  filtersActive,
  visibleCount,
  totalCount,
}: {
  meta: PivotMeta
  trailingColumnCount: number
  columnFilters: PivotColumnFilters
  onFilterChange: (key: PivotDimKey, value: string) => void
  onClearFilters: () => void
  filtersActive: boolean
  visibleCount: number
  totalCount: number
}) {
  const flagStart = trailingColumnCount - (meta.flags ? PIVOT_FLAG_KEYS.length : 0)

  return (
    <thead>
      <tr>
        {PIVOT_STICKY_COLS.map((col, i) => (
          <th
            key={col.key}
            style={{
              ...stickyColStyle(i),
              top: 0,
              height: PIVOT_LABEL_HEADER_HEIGHT,
            }}
            className={cn(
              "sticky z-40 border-b bg-muted px-2 py-0 text-left align-bottom font-medium text-xs whitespace-nowrap",
              isLastStickyCol(i) && STICKY_HEADER_EDGE_SHADOW
            )}
          >
            <div className="flex h-full flex-col justify-end pb-1">
              <span className="leading-tight">{col.label}</span>
              <span className="h-2.5" aria-hidden />
            </div>
          </th>
        ))}
        {PIB_PIVOT_ASSET_COLUMNS.map((c) => (
          <PivotHeaderCell
            key={`${c.code}-${c.shortLabel}`}
            code={c.code}
            label={c.compactLabel}
            className="z-10 min-w-[6.75rem] text-right"
          />
        ))}
        <PivotHeaderCell label="TOTAL" className="z-10 min-w-[6.75rem] text-right font-semibold" />
        <PivotHeaderCell label="Loan / Overdraft" className="z-10 min-w-[6.75rem] text-right" />
        {meta.pickUp ? (
          <PivotHeaderCell label="Pick up" className="z-10 min-w-[5.5rem] text-right" />
        ) : null}
        {meta.error ? (
          <PivotHeaderCell label="Error" className="z-10 min-w-[4.5rem] text-right" />
        ) : null}
        {meta.classification ? (
          <PivotHeaderCell label="Classification" className="z-10 min-w-[7rem]" />
        ) : null}
        {meta.flags
          ? PIVOT_FLAG_KEYS.map((flag) => (
              <th
                key={flag}
                style={{ top: 0, height: PIVOT_LABEL_HEADER_HEIGHT }}
                className="sticky z-30 w-8 border-b bg-muted px-1 py-0 text-center align-bottom font-medium text-[10px] whitespace-nowrap"
              >
                <div className="flex h-full flex-col justify-end pb-1">
                  <span className="leading-tight">{flag.toUpperCase()}</span>
                  <span className="h-2.5" aria-hidden />
                </div>
              </th>
            ))
          : null}
      </tr>
      <tr className="bg-muted/40">
        {PIVOT_STICKY_COLS.map((col, i) => (
          <th
            key={`filter-${col.key}`}
            style={{
              ...stickyColStyle(i),
              top: PIVOT_FILTER_HEADER_TOP,
            }}
            className={cn(
              "sticky z-40 border-b bg-muted p-0.5 align-middle font-normal",
              isLastStickyCol(i) && STICKY_HEADER_EDGE_SHADOW
            )}
          >
            <Input
              value={columnFilters[col.key]}
              onChange={(e) => onFilterChange(col.key, e.target.value)}
              placeholder="Filter…"
              aria-label={`Filter ${col.label}`}
              className="h-7 min-w-0 rounded-md border-border/70 bg-background px-1.5 text-xs font-normal shadow-none placeholder:font-normal placeholder:text-muted-foreground/60"
            />
          </th>
        ))}
        {/* One cell per trailing column (same count/widths as header+body).
            A single colSpan "Clear filters" cell used to stretch the grid. */}
        {Array.from({ length: trailingColumnCount }, (_, i) => {
          const isFlagCol = meta.flags && i >= flagStart
          return (
            <th
              key={`filter-amt-${i}`}
              style={{
                top: PIVOT_FILTER_HEADER_TOP,
                ...(isFlagCol ? { width: 32, minWidth: 32, maxWidth: 32 } : AMOUNT_COL_STYLE),
              }}
              className={cn(
                "sticky z-30 border-b bg-muted py-0.5 align-middle font-normal",
                isFlagCol ? "w-8 px-0.5" : "px-1 text-left"
              )}
            >
              {i === 0 ? (
                filtersActive ? (
                  <button
                    type="button"
                    onClick={onClearFilters}
                    title={`Clear filters (${visibleCount}/${totalCount})`}
                    className="inline-flex h-7 max-w-full items-center gap-1 truncate rounded-md px-1.5 text-[11px] font-medium text-muted-foreground hover:bg-background hover:text-foreground"
                  >
                    <X className="size-3.5 shrink-0" />
                    <span className="truncate">
                      Clear ({visibleCount}/{totalCount})
                    </span>
                  </button>
                ) : (
                  <span className="px-1 text-[11px] text-muted-foreground">Filter…</span>
                )
              ) : null}
            </th>
          )
        })}
      </tr>
    </thead>
  )
}

function PivotSheetRow({
  row,
  meta,
  groupSize,
  groupIndex,
  onDrill,
}: {
  row: PibPivotRow
  meta: PivotMeta
  groupSize: number
  groupIndex: number
  onDrill?: OpenDetail
}) {
  const total = pivotAssetTotal(row)
  const dimValues = pivotDimValues(row)
  const isMultiCustomer = groupSize >= 2
  const isGroupStart = isMultiCustomer && groupIndex === 0
  const isGroupCont = isMultiCustomer && groupIndex > 0
  const hasCustomer = (row.customerId ?? 0) > 0

  return (
    <tr
      className={cn(
        "border-b border-border/50 last:border-0",
        isGroupStart && "border-t border-t-border/80",
        isMultiCustomer && "bg-muted/[0.18]"
      )}
    >
      {PIVOT_STICKY_COLS.map((col, i) => {
        const isClient = col.key === "client"
        // Every row carries its own Residency / RM / Ac Type / Jurisdiction / Bank / Client —
        // blanking repeats made later rows of a client look like missing data.
        const text = dimValues[i]
        return (
          <td
            key={col.key}
            style={stickyColStyle(i)}
            title={
              col.key === "rm"
                ? row.rmName?.trim() || text || undefined
                : isClient && isGroupCont
                  ? row.client || undefined
                  : text || undefined
            }
            className={cn(
              "sticky z-30 overflow-hidden text-ellipsis bg-background px-2 py-1.5 text-xs whitespace-nowrap",
              isMultiCustomer && "bg-muted",
              isClient && isMultiCustomer && "border-l-2 border-l-emerald-600/50",
              col.key === "bank" && "font-medium",
              isClient &&
                row.clientHighlight &&
                "bg-amber-100 font-medium dark:bg-amber-950",
              isClient && "font-medium",
              isLastStickyCol(i) && STICKY_EDGE_SHADOW
            )}
          >
            {text}
          </td>
        )
      })}
      {PIB_PIVOT_ASSET_COLUMNS.map((c) => {
        const v = row[c.key] as number | null
        const bucketKey = c.key as PibPivotAssetBucketKey
        const unmappedCount = pivotUnmappedCount(row, bucketKey)
        const potentialCount = pivotPotentialCount(row, bucketKey)
        const bankMissingCount = pivotBankMissingCount(row, bucketKey)
        const canDrill =
          onDrill && hasCustomer && (isDrillableAmount(v) || bankMissingCount > 0)
        return (
          <td
            key={`${c.code}-${c.shortLabel}`}
            style={AMOUNT_COL_STYLE}
            className={cn(
              CELL_PAD,
              "relative z-0 text-right whitespace-nowrap",
              aumClass(v),
              unmappedCount > 0 && "bg-amber-50 dark:bg-amber-950/40",
              unmappedCount === 0 &&
                potentialCount > 0 &&
                "bg-amber-500/5 dark:bg-amber-500/10",
              unmappedCount === 0 &&
                potentialCount === 0 &&
                bankMissingCount > 0 &&
                "bg-rose-500/5 dark:bg-rose-500/10"
            )}
          >
            <PivotAmountCell
              value={v}
              unmappedCount={unmappedCount}
              inferredValue={pivotInferredValue(row, bucketKey)}
              potentialCount={potentialCount}
              potentialValue={pivotPotentialValue(row, bucketKey)}
              bankMissingCount={bankMissingCount}
              bankMissingValue={pivotBankMissingValue(row, bucketKey)}
              canDrill={Boolean(canDrill)}
              drillTitle={`View ${c.shortLabel} holdings`}
              onDrill={
                canDrill
                  ? () => onDrill(row, c.key, c.shortLabel, typeof v === "number" ? v : 0)
                  : undefined
              }
            />
          </td>
        )
      })}
      <td
        className={cn(
          CELL_PAD,
          "relative z-0 text-right font-semibold tabular-nums whitespace-nowrap"
        )}
        style={AMOUNT_COL_STYLE}
      >
        {formatPibValue(total)}
      </td>
      <td
        className={cn(
          CELL_PAD,
          "relative z-0 text-right whitespace-nowrap",
          aumClass(row.loanLiability)
        )}
        style={AMOUNT_COL_STYLE}
      >
        {onDrill && hasCustomer && isDrillableAmount(row.loanLiability) ? (
          <button
            type="button"
            className="w-full text-right underline-offset-2 hover:text-primary hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
            title="View Loan / Overdraft holdings"
            onClick={() =>
              onDrill(row, PIB_PIVOT_LOAN_BUCKET, "Loan / Overdraft", row.loanLiability as number)
            }
          >
            {formatPibValue(row.loanLiability)}
          </button>
        ) : (
          formatPibValue(row.loanLiability)
        )}
      </td>
      {meta.pickUp ? (
        <td
          className={cn(CELL_PAD, "text-right tabular-nums whitespace-nowrap")}
          style={AMOUNT_COL_STYLE}
        >
          {formatPibValue(row.pickUpTotalFromSumm)}
        </td>
      ) : null}
      {meta.error ? (
        <td
          className={cn(
            CELL_PAD,
            "text-right tabular-nums text-muted-foreground whitespace-nowrap"
          )}
          style={AMOUNT_COL_STYLE}
        >
          {row.error == null ? "" : String(row.error)}
        </td>
      ) : null}
      {meta.classification ? (
        <td
          className={cn(CELL_PAD, "truncate whitespace-nowrap")}
          style={{
            ...AMOUNT_COL_STYLE,
            maxWidth: PIVOT_AMOUNT_COL_MIN_WIDTH,
          }}
          title={row.classification || undefined}
        >
          {row.classification}
        </td>
      ) : null}
      {meta.flags
        ? PIVOT_FLAG_KEYS.map((flag) => (
            <td key={flag} className="px-0.5 py-0.5 text-center text-[10px] text-muted-foreground">
              {row.flags[flag]}
            </td>
          ))
        : null}
    </tr>
  )
}

function PivotAmountCell({
  value,
  unmappedCount,
  inferredValue,
  potentialCount,
  potentialValue,
  bankMissingCount,
  bankMissingValue,
  canDrill,
  drillTitle,
  onDrill,
}: {
  value: number | null
  unmappedCount: number
  inferredValue: number
  potentialCount: number
  potentialValue: number
  bankMissingCount: number
  bankMissingValue: number
  canDrill: boolean
  drillTitle?: string
  onDrill?: () => void
}) {
  const hasUnmapped = unmappedCount > 0
  const hasBankMissing = bankMissingCount > 0
  const titles = pivotAmountCellTitles({
    value,
    unmappedCount,
    inferredValue,
    potentialCount,
    potentialValue,
    bankMissingCount,
    bankMissingValue,
  })

  return (
    <div className="flex items-center justify-end gap-1">
      {hasUnmapped ? (
        <span
          className="size-1.5 shrink-0 rounded-full bg-amber-500 ring-2 ring-amber-500/25"
          title={titles.unmapped}
          aria-label={titles.unmapped}
        />
      ) : null}
      {potentialCount > 0 ? (
        <ReportLifecycleBadge
          kind="potential"
          title={titles.potential}
          className="shrink-0"
        />
      ) : null}
      {hasBankMissing ? (
        <span
          className="inline-flex h-5 shrink-0 items-center rounded-md border border-rose-500/30 bg-rose-500/10 px-1.5 text-[10px] font-semibold uppercase tracking-wide text-rose-800 dark:text-rose-200"
          title={titles.bankMissing}
          aria-label={titles.bankMissing}
        >
          No MP/FX
        </span>
      ) : null}
      {canDrill && onDrill ? (
        <button
          type="button"
          className={cn(
            "text-right underline-offset-2 hover:text-primary hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
            hasUnmapped && "font-medium text-amber-900 dark:text-amber-200",
            !hasUnmapped && hasBankMissing && "font-medium text-rose-900 dark:text-rose-200"
          )}
          title={drillTitle ?? titles.combined}
          onClick={onDrill}
        >
          {/* Missing-only cells have null amounts; show 0.00 so the badge/drill stay visible. */}
          {formatPibValue(hasBankMissing && value == null ? 0 : value)}
        </button>
      ) : (
        <span
          className={cn(
            hasUnmapped && "font-medium text-amber-900 dark:text-amber-200",
            !hasUnmapped && hasBankMissing && "font-medium text-rose-900 dark:text-rose-200"
          )}
          title={titles.combined}
        >
          {formatPibValue(hasBankMissing && value == null ? 0 : value)}
        </span>
      )}
    </div>
  )
}

/** Sticky totals row over the visible (filtered) rows. */
function PivotSheetTotals({
  meta,
  totals,
}: {
  meta: PivotMeta
  totals: ReturnType<typeof sumPivotColumnTotals>
}) {
  return (
    <tfoot>
      <tr className="border-t-2 border-border">
        {PIVOT_STICKY_COLS.map((col, i) => (
          <td
            key={`total-${col.key}`}
            style={{
              ...stickyColStyle(i),
              bottom: 0,
            }}
            className={cn(
              "sticky z-30 bg-muted px-2 py-1.5 text-xs font-semibold whitespace-nowrap",
              isLastStickyCol(i) && STICKY_EDGE_SHADOW
            )}
          >
            {i === 0 ? "Total" : ""}
          </td>
        ))}
        {PIB_PIVOT_ASSET_COLUMNS.map((c) => {
          const v = totals.assets[c.key]
          return (
            <td key={`total-${c.key}`} className={cn(CELL_PAD, TOTALS_AMOUNT_CELL, aumClass(v))}>
              {formatPibValue(v)}
            </td>
          )
        })}
        <td className={cn(CELL_PAD, TOTALS_AMOUNT_CELL)}>
          {formatPibValue(totals.total)}
        </td>
        <td className={cn(CELL_PAD, TOTALS_AMOUNT_CELL, aumClass(totals.loanLiability))}>
          {formatPibValue(totals.loanLiability)}
        </td>
        {meta.pickUp ? (
          <td className={cn(CELL_PAD, TOTALS_AMOUNT_CELL)}>
            {formatPibValue(totals.pickUp)}
          </td>
        ) : null}
        {meta.error ? (
          <td className="sticky bottom-0 z-20 bg-muted px-2 py-1.5" />
        ) : null}
        {meta.classification ? (
          <td className="sticky bottom-0 z-20 bg-muted px-2 py-1.5" />
        ) : null}
        {meta.flags
          ? PIVOT_FLAG_KEYS.map((flag) => (
              <td key={`total-flag-${flag}`} className="sticky bottom-0 z-20 bg-muted px-0.5 py-0.5" />
            ))
          : null}
      </tr>
    </tfoot>
  )
}
