"use client"

import * as React from "react"
import Link from "next/link"
import { useRouter } from "next/navigation"
import {
  flexRender,
  getCoreRowModel,
  getFilteredRowModel,
  getPaginationRowModel,
  getSortedRowModel,
  useReactTable,
  type ColumnDef,
  type ColumnFiltersState,
  type PaginationState,
  type RowSelectionState,
  type SortingState,
} from "@tanstack/react-table"
import { ArrowDown, ArrowUp, ArrowUpDown } from "lucide-react"

import { Button } from "@/components/ui/button"
import { Checkbox } from "@/components/ui/checkbox"
import { Input } from "@/components/ui/input"
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table"
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { XmlApiTablePagination } from "@/components/xml-apis/shared/xml-api-table-pagination"
import { SETTINGS_INPUT_CLASS } from "@/components/settings/constants"
import { dashboardCsrfHeader } from "@/lib/csrf.client"
import { cn } from "@/lib/utils"

import { LIST_HREF, type IsinAssetMasterRow } from "./schema"
import { IsinAssetMasterPibSelect } from "./isin-asset-master-pib-select"
import {
  formatPibOption,
  type PibClassOption,
} from "../_lib/pib-class-options"
import { formatPlainAmount } from "@/lib/format/numbers"

type Props = {
  data: IsinAssetMasterRow[]
  totalCount: number
  pibClassList: PibClassOption[]
}

const filterInputClass = cn(SETTINGS_INPUT_CLASS, "h-8")
const BULK_HREF = `${LIST_HREF}/bulk-update-pib`
const ALL_AC = "__all__"

type PibTab = "unassigned" | "assigned"

type AssetClassGroup = {
  code: string
  label: string
  count: number
}

export function IsinAssetMasterTable({ data, totalCount, pibClassList }: Props) {
  const router = useRouter()
  const [pibTab, setPibTab] = React.useState<PibTab>("unassigned")
  const [aClassFilter, setAClassFilter] = React.useState<string>(ALL_AC)
  const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([
    { id: "pibClass", value: "empty" },
  ])
  const [rowSelection, setRowSelection] = React.useState<RowSelectionState>({})
  const [sorting, setSorting] = React.useState<SortingState>([
    { id: "confidenceAc", desc: true },
  ])
  const [pagination, setPagination] = React.useState<PaginationState>({
    pageIndex: 0,
    pageSize: 20,
  })
  const [bulkPib, setBulkPib] = React.useState("")
  const [bulkBusy, setBulkBusy] = React.useState(false)
  const [bulkError, setBulkError] = React.useState<string | null>(null)
  const [bulkMessage, setBulkMessage] = React.useState<string | null>(null)

  const unassignedCount = React.useMemo(
    () => data.filter((row) => !row.pibClass).length,
    [data]
  )
  const assignedCount = React.useMemo(
    () => data.filter((row) => Boolean(row.pibClass)).length,
    [data]
  )

  const tabRows = React.useMemo(() => {
    return data.filter((row) =>
      pibTab === "unassigned" ? !row.pibClass : Boolean(row.pibClass)
    )
  }, [data, pibTab])

  const assetClassGroups = React.useMemo((): AssetClassGroup[] => {
    const map = new Map<string, AssetClassGroup>()
    for (const row of tabRows) {
      const code = row.aClass || "(empty)"
      const existing = map.get(code)
      if (existing) {
        existing.count += 1
        continue
      }
      map.set(code, {
        code,
        label: row.aClassLabel || code,
        count: 1,
      })
    }
    return Array.from(map.values()).sort((a, b) => {
      if (b.count !== a.count) return b.count - a.count
      return a.label.localeCompare(b.label)
    })
  }, [tabRows])

  const columns = React.useMemo<ColumnDef<IsinAssetMasterRow>[]>(
    () => [
      {
        id: "select",
        enableSorting: false,
        enableHiding: false,
        size: 40,
        header: ({ table }) => (
          <Checkbox
            checked={
              table.getIsAllPageRowsSelected()
                ? true
                : table.getIsSomePageRowsSelected()
                  ? "indeterminate"
                  : false
            }
            onCheckedChange={(value) => table.toggleAllPageRowsSelected(value === true)}
            aria-label="Select all on page"
          />
        ),
        cell: ({ row }) => (
          <Checkbox
            checked={row.getIsSelected()}
            onCheckedChange={(value) => row.toggleSelected(value === true)}
            aria-label={`Select ${row.original.isin}`}
            className="mt-0.5"
          />
        ),
      },
      {
        accessorKey: "isin",
        header: "ISIN",
        cell: ({ row }) => {
          const names = [
            row.original.isinName,
            ...row.original.isinNames,
          ].filter((n, i, arr) => n && arr.indexOf(n) === i)

          return (
            <div className="flex min-w-0 max-w-full flex-col items-start gap-1.5">
              <Link
                href={`${LIST_HREF}/${row.original.id}`}
                className="inline-flex items-center gap-1.5 font-mono text-sm text-sky-700 hover:underline"
              >
                <span>{row.original.isin}</span>
                <span className="rounded-md bg-muted px-1.5 py-0.5 font-sans text-[11px] font-medium text-muted-foreground no-underline">
                  {row.original.bankCount}
                </span>
              </Link>
              {names.length > 0 ? (
                <div className="flex w-full flex-col items-start gap-1">
                  {names.map((name) => (
                    <span
                      key={name}
                      className="inline-block max-w-full rounded-md bg-secondary px-2 py-0.5 text-left text-xs font-normal leading-snug text-secondary-foreground whitespace-normal break-words"
                      title={name}
                    >
                      {name}
                    </span>
                  ))}
                </div>
              ) : null}
            </div>
          )
        },
      },
      {
        accessorKey: "bankCount",
        header: "Banks",
        cell: ({ row }) => (
          <div className="flex min-w-0 max-w-full flex-col flex-wrap items-start gap-1">
            {row.original.bankNames.length > 0 ? (
              row.original.bankNames.map((name) => (
                <span
                  key={name}
                  className="inline-block max-w-full rounded-md border border-border bg-background px-2 py-0.5 text-left text-xs font-normal leading-snug whitespace-normal break-words"
                  title={name}
                >
                  {name}
                </span>
              ))
            ) : (
              <span className="tabular-nums text-sm text-muted-foreground">
                {row.original.bankCount}
              </span>
            )}
          </div>
        ),
      },
      {
        accessorKey: "aClass",
        header: "Asset Class",
        filterFn: (row, _columnId, filterValue) => {
          if (!filterValue || filterValue === ALL_AC) return true
          const code = row.original.aClass || "(empty)"
          return code === filterValue
        },
        cell: ({ row }) => (
          <span className="text-sm">
            {row.original.aClassLabel}
            {row.original.aClass ? (
              <span className="ml-1 font-mono text-xs text-muted-foreground">
                ({row.original.aClass})
              </span>
            ) : null}
          </span>
        ),
      },
      { accessorKey: "aType", header: "Asset Type" },
      {
        accessorKey: "pibClass",
        header: "PIB",
        filterFn: (row, _columnId, filterValue) => {
          const hasPib = Boolean(row.original.pibClass)
          if (filterValue === "empty") return !hasPib
          if (filterValue === "assigned") return hasPib
          return true
        },
        cell: ({ row }) => (
          <IsinAssetMasterPibSelect
            id={row.original.id}
            value={row.original.pibClass}
            options={pibClassList}
          />
        ),
      },
      { accessorKey: "statusLabel", header: "Status", enableSorting: false },
      {
        accessorKey: "confidenceAc",
        header: ({ column }) => {
          const sorted = column.getIsSorted()
          return (
            <button
              type="button"
              className="inline-flex items-center gap-1 font-medium hover:text-foreground"
              onClick={() => column.toggleSorting(sorted === "asc")}
            >
              Confidence %
              {sorted === "desc" ? (
                <ArrowDown className="size-3.5" />
              ) : sorted === "asc" ? (
                <ArrowUp className="size-3.5" />
              ) : (
                <ArrowUpDown className="size-3.5 opacity-50" />
              )}
            </button>
          )
        },
        sortingFn: (a, b) => {
          const av = a.original.confidenceAc
          const bv = b.original.confidenceAc
          if (av == null && bv == null) return 0
          if (av == null) return 1
          if (bv == null) return -1
          return av - bv
        },
        cell: ({ row }) =>
          row.original.confidenceAc == null ? "—" : String(row.original.confidenceAc),
      },
      { accessorKey: "updatedAt", header: "Updated", enableSorting: false },
    ],
    [pibClassList]
  )

  const table = useReactTable({
    data,
    columns,
    state: { columnFilters, pagination, rowSelection, sorting },
    getRowId: (r) => r.id,
    enableRowSelection: true,
    onRowSelectionChange: setRowSelection,
    onColumnFiltersChange: setColumnFilters,
    onPaginationChange: setPagination,
    onSortingChange: setSorting,
    getCoreRowModel: getCoreRowModel(),
    getFilteredRowModel: getFilteredRowModel(),
    getSortedRowModel: getSortedRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
  })

  const filteredCount = table.getFilteredRowModel().rows.length
  const selectedIds = Object.keys(rowSelection).filter((id) => rowSelection[id])
  const selectedCount = selectedIds.length
  const pageIndex = table.getState().pagination.pageIndex
  const pageSize = table.getState().pagination.pageSize
  const start = filteredCount === 0 ? 0 : pageIndex * pageSize + 1
  const end = Math.min((pageIndex + 1) * pageSize, filteredCount)

  const headers = table.getHeaderGroups()[0]?.headers ?? []
  const activeGroup = assetClassGroups.find((g) => g.code === aClassFilter) ?? null

  function setFilters(nextPib: PibTab, nextAClass: string) {
    setColumnFilters([
      { id: "pibClass", value: nextPib === "unassigned" ? "empty" : "assigned" },
      ...(nextAClass !== ALL_AC ? [{ id: "aClass", value: nextAClass }] : []),
    ])
  }

  function onPibTabChange(value: string) {
    const next = value === "assigned" ? "assigned" : "unassigned"
    setPibTab(next)
    setAClassFilter(ALL_AC)
    setRowSelection({})
    setBulkMessage(null)
    setBulkError(null)
    setFilters(next, ALL_AC)
    setPagination((prev) => ({ ...prev, pageIndex: 0 }))
  }

  function onAClassChange(code: string) {
    setAClassFilter(code)
    setRowSelection({})
    setBulkMessage(null)
    setBulkError(null)
    setFilters(pibTab, code)
    setPagination((prev) => ({ ...prev, pageIndex: 0 }))
  }

  async function applyBulkPib() {
    if (selectedCount === 0 || bulkBusy) return
    if (selectedCount > 500) {
      setBulkError("Maximum 500 rows per bulk update. Narrow selection first.")
      return
    }
    setBulkBusy(true)
    setBulkError(null)
    setBulkMessage(null)
    try {
      const res = await fetch(BULK_HREF, {
        method: "POST",
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json",
          ...dashboardCsrfHeader(),
        },
        body: JSON.stringify({
          ids: selectedIds,
          pib_class: bulkPib,
        }),
      })
      const json = await res.json().catch(() => ({}))
      if (!res.ok || json?.status === "error") {
        throw new Error(json?.message || "Could not mass-assign PIB.")
      }
      setBulkMessage(json?.message || `Updated ${selectedCount} row(s).`)
      setRowSelection({})
      router.refresh()
    } catch (e) {
      setBulkError(e instanceof Error ? e.message : "Could not mass-assign PIB.")
    } finally {
      setBulkBusy(false)
    }
  }

  const emptyMessage =
    data.length === 0
      ? "No master rows yet. Save Safra positions to seed votes."
      : aClassFilter !== ALL_AC
        ? "No rows in this asset class for the current tab."
        : pibTab === "unassigned"
          ? "No unassigned PIB rows."
          : "No assigned PIB rows."

  return (
    <div className="space-y-4">
      <Tabs value={pibTab} onValueChange={onPibTabChange}>
        <TabsList>
          <TabsTrigger value="unassigned">
            Unassigned ({formatPlainAmount(unassignedCount)})
          </TabsTrigger>
          <TabsTrigger value="assigned">
            Assigned ({formatPlainAmount(assignedCount)})
          </TabsTrigger>
        </TabsList>
      </Tabs>

      <div className="space-y-2">
        <p className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
          Asset class groups
        </p>
        <div className="flex flex-wrap gap-1.5">
          <button
            type="button"
            onClick={() => onAClassChange(ALL_AC)}
            className={cn(
              "rounded-full border px-3 py-1 text-xs transition-colors",
              aClassFilter === ALL_AC
                ? "border-primary bg-primary text-primary-foreground"
                : "border-border bg-background text-foreground hover:bg-muted"
            )}
          >
            All ({formatPlainAmount(tabRows.length)})
          </button>
          {assetClassGroups.map((group) => (
            <button
              key={group.code}
              type="button"
              onClick={() => onAClassChange(group.code)}
              className={cn(
                "rounded-full border px-3 py-1 text-xs transition-colors",
                aClassFilter === group.code
                  ? "border-primary bg-primary text-primary-foreground"
                  : "border-border bg-background text-foreground hover:bg-muted"
              )}
              title={`${group.label} (${group.code})`}
            >
              {group.label}
              {group.code !== group.label && group.code !== "(empty)" ? (
                <span className="opacity-80"> ({group.code})</span>
              ) : null}{" "}
              · {formatPlainAmount(group.count)}
            </button>
          ))}
        </div>
      </div>

      <div className="flex flex-wrap items-center gap-2">
        <Input
          className={cn(filterInputClass, "max-w-xs")}
          placeholder="Filter ISIN…"
          value={(table.getColumn("isin")?.getFilterValue() as string) ?? ""}
          onChange={(e) => {
            table.getColumn("isin")?.setFilterValue(e.target.value || undefined)
            table.setPageIndex(0)
          }}
        />
        <p className="text-sm text-muted-foreground">
          Displaying {start}–{end} of {formatPlainAmount(filteredCount)}
          {activeGroup
            ? ` ${activeGroup.label}`
            : pibTab === "unassigned"
              ? " unassigned"
              : " assigned"}
          {data.length < totalCount
            ? ` (loaded ${formatPlainAmount(data.length)} of ${formatPlainAmount(totalCount)})`
            : ""}
          .
        </p>
      </div>

      <div className="flex flex-wrap items-center gap-2 rounded-lg border bg-muted/20 px-3 py-2">
        <span className="text-sm font-medium">
          {selectedCount > 0 ? `${selectedCount} selected` : "Mass assign PIB"}
        </span>
        <Button
          type="button"
          variant="outline"
          size="sm"
          disabled={filteredCount === 0}
          onClick={() => {
            const next: RowSelectionState = {}
            for (const row of table.getFilteredRowModel().rows) {
              next[row.id] = true
            }
            setRowSelection(next)
          }}
        >
          {activeGroup
            ? `Select ${activeGroup.label} (${filteredCount})`
            : `Select filtered (${filteredCount})`}
        </Button>
        <Button
          type="button"
          variant="ghost"
          size="sm"
          disabled={selectedCount === 0}
          onClick={() => setRowSelection({})}
        >
          Clear
        </Button>
        <select
          className={cn(
            "h-8 max-w-[18rem] rounded border border-input bg-background px-2 text-xs",
            "disabled:cursor-not-allowed disabled:opacity-50"
          )}
          value={bulkPib}
          disabled={bulkBusy || selectedCount === 0}
          onChange={(e) => setBulkPib(e.target.value)}
          aria-label="PIB class for mass assign"
        >
          <option value="">— Clear PIB —</option>
          {pibClassList.map((opt) => (
            <option key={opt.code} value={opt.code}>
              {formatPibOption(opt)}
            </option>
          ))}
        </select>
        <Button
          type="button"
          size="sm"
          disabled={bulkBusy || selectedCount === 0}
          onClick={() => void applyBulkPib()}
        >
          {bulkBusy ? "Applying…" : "Apply to selected"}
        </Button>
        {bulkMessage ? (
          <span className="text-sm text-emerald-700">{bulkMessage}</span>
        ) : null}
        {bulkError ? (
          <span className="text-sm text-destructive">{bulkError}</span>
        ) : null}
      </div>

      <div className="overflow-x-auto rounded-lg border bg-card">
        <Table>
          <TableHeader>
            <TableRow>
              {headers.map((header) => (
                <TableHead
                  key={header.id}
                  className={
                    header.column.id === "select"
                      ? "w-10 px-3"
                      : header.column.id === "isin" || header.column.id === "bankCount"
                        ? "whitespace-normal"
                        : undefined
                  }
                >
                  {header.isPlaceholder
                    ? null
                    : flexRender(header.column.columnDef.header, header.getContext())}
                </TableHead>
              ))}
            </TableRow>
          </TableHeader>
          <TableBody>
            {table.getRowModel().rows.length ? (
              table.getRowModel().rows.map((row) => (
                <TableRow key={row.id} data-state={row.getIsSelected() ? "selected" : undefined}>
                  {row.getVisibleCells().map((cell) => (
                    <TableCell
                      key={cell.id}
                      className={
                        cell.column.id === "select"
                          ? "w-10 align-top px-3"
                          : cell.column.id === "isin" || cell.column.id === "bankCount"
                            ? "align-top whitespace-normal"
                            : "align-top"
                      }
                    >
                      {flexRender(cell.column.columnDef.cell, cell.getContext())}
                    </TableCell>
                  ))}
                </TableRow>
              ))
            ) : (
              <TableRow>
                <TableCell colSpan={columns.length} className="h-24 text-center text-muted-foreground">
                  {emptyMessage}
                </TableCell>
              </TableRow>
            )}
          </TableBody>
        </Table>
      </div>
      <XmlApiTablePagination table={table} pageSizeOptions={[10, 20, 50, 100, 500]} />
    </div>
  )
}
