'use client'

import * as React from 'react'
import type { ColumnDef, ColumnFiltersState, RowData, SortingState } from '@tanstack/react-table'
import {
  DataGrid,
  DataGridBody,
  DataGridCell,
  DataGridHead,
  DataGridHeader,
  DataGridRow
} from '@admin/components/shared/data-table/data-grid'
import { useTableUtils } from '@admin/hooks/use-table-utils'
import { cn } from '@admin/utils/shared/cn'
import {
  flexRender,
  getCoreRowModel,
  getFilteredRowModel,
  getPaginationRowModel,
  getSortedRowModel,
  useReactTable
} from '@tanstack/react-table'
import { GripVertical } from 'lucide-react'
import { parseAsInteger, useQueryState } from 'nuqs'
import { DataTablePagination } from './data-table-pagination'

interface DataTableProps<TData extends RowData, TValue> {
  columns: ColumnDef<TData, TValue>[]
  data: TData[]
  isPending?: boolean
  error?: Error | null
  emptyMessage?: string
  loadingMessage?: string
  selectedIds?: string[]
  onSelectedIdsChange?: (ids: string[]) => void
  meta?: Record<string, unknown>
  getId?: (row: TData) => string
}

export function DataTable<TData extends RowData, TValue>({
  columns,
  data,
  isPending = false,
  error = null,
  emptyMessage = 'No results found.',
  loadingMessage = 'Loading…',
  selectedIds,
  onSelectedIdsChange,
  meta,
  getId
}: DataTableProps<TData, TValue>) {
  const [sorting, setSorting] = React.useState<SortingState>([])
  const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])
  const [pageIndex, setPageIndex] = useQueryState('page', parseAsInteger.withDefault(0))
  const [pageSize, setPageSize] = useQueryState('size', parseAsInteger.withDefault(20))
  const effectivePageSize = pageSize === -1 ? Number.MAX_SAFE_INTEGER : pageSize
  const {
    columnSizing,
    handleColumnSizingChange,
    handlePaginationChange,
    handleRowSelectionChange,
    hoveredColumnId,
    registerTable,
    resetColumnSizingToContainer,
    rowSelection,
    setHoveredColumnId,
    tableContainerRef
  } = useTableUtils<TData>({
    data,
    getId,
    onSelectedIdsChange,
    pageIndex,
    pageSize: effectivePageSize,
    selectedIds,
    setPageIndex
  })

  const table = useReactTable({
    data,
    columns,
    columnResizeMode: 'onChange',
    defaultColumn: {
      minSize: 48,
      size: 220
    },
    getCoreRowModel: getCoreRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
    onSortingChange: setSorting,
    getSortedRowModel: getSortedRowModel(),
    onColumnFiltersChange: setColumnFilters,
    getFilteredRowModel: getFilteredRowModel(),
    onColumnSizingChange: handleColumnSizingChange,
    onRowSelectionChange: selectedIds ? handleRowSelectionChange : undefined,
    onPaginationChange: handlePaginationChange,
    meta,
    state: {
      sorting,
      columnFilters,
      columnSizing,
      rowSelection,
      pagination: {
        pageIndex,
        pageSize: effectivePageSize
      }
    }
  })
  registerTable(table)
  const gridTemplateColumns = table
    .getVisibleLeafColumns()
    .map((column) => `${column.getSize()}px`)
    .join(' ')

  return (
    <div className="space-y-6 pb-24">
      <DataGrid
        containerRef={tableContainerRef}
        gridTemplateColumns={gridTemplateColumns}
        style={{ width: table.getTotalSize() }}
      >
        <DataGridHeader>
          {table.getHeaderGroups().map((headerGroup) => (
            <DataGridRow key={headerGroup.id}>
              {headerGroup.headers.map((header, headerIndex) => {
                const meta = header.column.columnDef.meta as Record<string, unknown> | undefined
                const resizeLabel =
                  typeof header.column.columnDef.header === 'string'
                    ? header.column.columnDef.header
                    : header.column.id
                const nextHeader = headerGroup.headers[headerIndex + 1]
                const canResizeColumn =
                  header.column.getCanResize() && nextHeader?.column.getCanResize() === true
                return (
                  <DataGridHead
                    key={header.id}
                    className={cn('group/resize-header relative overflow-hidden', {
                      'text-center': meta?.align === 'center',
                      'text-right': meta?.align === 'right'
                    })}
                    data-column-id={header.column.id}
                    onMouseEnter={() => setHoveredColumnId(header.column.id)}
                    onMouseLeave={() =>
                      setHoveredColumnId((current) =>
                        current === header.column.id ? null : current
                      )
                    }
                  >
                    {header.isPlaceholder
                      ? null
                      : flexRender(header.column.columnDef.header, header.getContext())}
                    {canResizeColumn ? (
                      <button
                        type="button"
                        aria-label={`Resize ${resizeLabel} column`}
                        className="group/resize-handle absolute top-0 right-0 z-10 flex h-full w-5 cursor-col-resize touch-none items-center justify-center text-foreground opacity-0 transition-opacity select-none group-focus-within/resize-header:opacity-100 focus-visible:opacity-100 focus-visible:outline-none data-[column-hovered=true]:opacity-100 data-[resizing=true]:opacity-100"
                        data-resize-handle
                        data-column-hovered={
                          hoveredColumnId === header.column.id ? 'true' : 'false'
                        }
                        data-resizing={header.column.getIsResizing() ? 'true' : 'false'}
                        onDoubleClick={resetColumnSizingToContainer}
                        onMouseDown={header.getResizeHandler()}
                        onTouchStart={header.getResizeHandler()}
                      >
                        <GripVertical aria-hidden="true" className="size-3.5 text-foreground" />
                      </button>
                    ) : null}
                  </DataGridHead>
                )
              })}
            </DataGridRow>
          ))}
        </DataGridHeader>
        <DataGridBody>
          {isPending ? (
            <DataGridRow>
              <DataGridCell
                className="flex h-24 items-center justify-center text-center"
                style={{ gridColumn: '1 / -1' }}
              >
                <div className="text-muted-foreground">{loadingMessage}</div>
              </DataGridCell>
            </DataGridRow>
          ) : error ? (
            <DataGridRow>
              <DataGridCell
                className="flex h-24 items-center justify-center text-center"
                style={{ gridColumn: '1 / -1' }}
              >
                <div className="text-destructive">
                  Failed to load these results. Refresh to try again.
                </div>
              </DataGridCell>
            </DataGridRow>
          ) : table.getRowModel().rows?.length ? (
            table.getRowModel().rows.map((row) => (
              <DataGridRow
                key={row.id}
                className="hover:bg-muted/50"
                data-state={row.getIsSelected() ? 'selected' : undefined}
              >
                {row.getVisibleCells().map((cell) => {
                  const meta = cell.column.columnDef.meta as Record<string, unknown> | undefined
                  return (
                    <DataGridCell
                      key={cell.id}
                      className={cn({
                        'text-center': meta?.align === 'center',
                        'text-right': meta?.align === 'right'
                      })}
                      data-column-id={cell.column.id}
                      onMouseEnter={() => setHoveredColumnId(cell.column.id)}
                      onMouseLeave={() =>
                        setHoveredColumnId((current) =>
                          current === cell.column.id ? null : current
                        )
                      }
                    >
                      {flexRender(cell.column.columnDef.cell, cell.getContext())}
                    </DataGridCell>
                  )
                })}
              </DataGridRow>
            ))
          ) : (
            <DataGridRow>
              <DataGridCell
                className="flex h-24 items-center justify-center text-center"
                style={{ gridColumn: '1 / -1' }}
              >
                {emptyMessage}
              </DataGridCell>
            </DataGridRow>
          )}
        </DataGridBody>
      </DataGrid>

      <DataTablePagination
        table={table}
        paginationMode="uncontrolled"
        pageSize={pageSize}
        setPageSize={setPageSize}
      />
    </div>
  )
}

export type { DataTableProps }
