import * as React from 'react'
import {
  type ColumnDef,
  type SortingState,
  type ColumnFiltersState,
  flexRender,
  getCoreRowModel,
  getSortedRowModel,
  getFilteredRowModel,
  useReactTable,
} from '@tanstack/react-table'
import { ChevronDown, ChevronUp, ChevronsUpDown } from 'lucide-react'
import { cn } from '../lib/cn'
import { Table, Thead, Tbody, Tr, Th, Td } from './table'
import { Input } from '../primitives/input'
import { Skeleton } from '../primitives/skeleton'
import { PaginationControls, type DataTablePagination } from './pagination-controls'

export type { DataTablePagination }

export interface DataTableProps<TData> {
  columns: ColumnDef<TData>[]
  data: TData[]
  /**
   * Structured cursor-based pagination. When omitted (e.g. bounded dashboard
   * lists), no pagination controls are rendered.
   * Replaces the former `pagination?: boolean` flag.
   */
  pagination?: DataTablePagination
  /** Current 1-based page number — required when `pagination` is supplied. */
  currentPage?: number
  sorting?: boolean
  filtering?: boolean | { column: string }
  tableLabel?: string
  /**
   * When true, renders static skeleton rows at real column widths in place of
   * real rows. No animate-pulse / shimmer (prefers-reduced-motion safe).
   */
  loading?: boolean
  /**
   * Number of skeleton rows to render while loading.
   * Callers should set this to their expected data density so there is no
   * layout shift (no CLS) on data arrival. Defaults to 5.
   */
  skeletonRowCount?: number
  /**
   * Rendered when !loading && data.length === 0. Supply an <EmptyState> from
   * the empty-state catalog.
   */
  emptyState?: React.ReactNode
  rowActions?: (row: TData) => React.ReactNode
  onRowClick?: (row: TData) => void
}

/**
 * TanStack Table v8 wrapper. Supports sorting, free-text filter, cursor-based
 * pagination controls, loading skeleton rows, empty state, per-row actions,
 * and row click.
 *
 * Loading skeletons: static (no animate-pulse) at real column widths.
 * Empty state: rendered when !loading && data.length === 0.
 * Pagination: structured cursor-based DataTablePagination object (not a boolean).
 */
export function DataTable<TData>({
  columns,
  data,
  pagination,
  currentPage = 1,
  sorting = true,
  filtering = true,
  tableLabel,
  loading = false,
  skeletonRowCount = 5,
  emptyState,
  rowActions,
  onRowClick,
}: DataTableProps<TData>) {
  const [sortingState, setSortingState] = React.useState<SortingState>([])
  const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])
  const [globalFilter, setGlobalFilter] = React.useState('')

  const filterColumn =
    typeof filtering === 'object' && filtering !== null ? filtering.column : undefined

  const table = useReactTable({
    data,
    columns,
    state: {
      sorting: sortingState,
      columnFilters,
      globalFilter: filterColumn ? undefined : globalFilter,
    },
    onSortingChange: setSortingState,
    onColumnFiltersChange: setColumnFilters,
    onGlobalFilterChange: setGlobalFilter,
    getCoreRowModel: getCoreRowModel(),
    ...(sorting ? { getSortedRowModel: getSortedRowModel() } : {}),
    ...(filtering ? { getFilteredRowModel: getFilteredRowModel() } : {}),
  })

  const rows = table.getRowModel().rows
  const visibleColumnCount = table.getAllLeafColumns().length + (rowActions ? 1 : 0)

  const handleFilterChange = (value: string) => {
    if (filterColumn) {
      table.getColumn(filterColumn)?.setFilterValue(value)
    } else {
      setGlobalFilter(value)
    }
  }

  return (
    <div className="flex flex-col gap-4">
      {filtering ? (
        <div className="max-w-screen-sm">
          <Input
            placeholder="Filter…"
            onChange={(e) => handleFilterChange(e.target.value)}
            aria-label="Filter table"
          />
        </div>
      ) : null}

      <Table aria-label={tableLabel}>
        <Thead>
          {table.getHeaderGroups().map((headerGroup) => (
            <Tr key={headerGroup.id}>
              {headerGroup.headers.map((header) => {
                const canSort = sorting && header.column.getCanSort()
                const sortDir = header.column.getIsSorted()
                return (
                  <Th key={header.id}>
                    {header.isPlaceholder ? null : canSort ? (
                      <button
                        type="button"
                        onClick={header.column.getToggleSortingHandler()}
                        className="inline-flex items-center gap-2 text-meta font-medium text-ink-soft hover:text-ink"
                      >
                        {flexRender(header.column.columnDef.header, header.getContext())}
                        {sortDir === 'asc' ? (
                          <ChevronUp className="h-4 w-4" aria-hidden="true" />
                        ) : sortDir === 'desc' ? (
                          <ChevronDown className="h-4 w-4" aria-hidden="true" />
                        ) : (
                          <ChevronsUpDown className="h-4 w-4 text-ink-faint" aria-hidden="true" />
                        )}
                      </button>
                    ) : (
                      flexRender(header.column.columnDef.header, header.getContext())
                    )}
                  </Th>
                )
              })}
              {rowActions ? <Th aria-label="Actions" /> : null}
            </Tr>
          ))}
        </Thead>
        <Tbody>
          {loading ? (
            // Static skeleton rows at real column widths — no animate-pulse.
            // animate-none overrides animate-pulse via tailwind-merge (cn).
            Array.from({ length: skeletonRowCount }).map((_, i) => (
              <Tr key={`skeleton-${i}`}>
                {Array.from({ length: visibleColumnCount }).map((__, j) => (
                  <Td key={`skeleton-${i}-${j}`}>
                    <Skeleton className="h-4 w-full animate-none" />
                  </Td>
                ))}
              </Tr>
            ))
          ) : rows.length === 0 ? (
            <Tr>
              <Td colSpan={visibleColumnCount}>
                <div className="py-8">{emptyState}</div>
              </Td>
            </Tr>
          ) : (
            rows.map((row) => (
              <Tr
                key={row.id}
                onClick={onRowClick ? () => onRowClick(row.original) : undefined}
                className={cn(onRowClick && 'cursor-pointer hover:bg-hover')}
              >
                {row.getVisibleCells().map((cell) => (
                  <Td key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</Td>
                ))}
                {rowActions ? (
                  <Td className="text-end" onClick={(e) => e.stopPropagation()}>
                    {rowActions(row.original)}
                  </Td>
                ) : null}
              </Tr>
            ))
          )}
        </Tbody>
      </Table>

      {pagination ? (
        <PaginationControls
          pagination={pagination}
          currentPage={currentPage}
        />
      ) : null}
    </div>
  )
}
