'use client';

import { useState } from 'react';
import {
  flexRender,
  getCoreRowModel,
  useReactTable,
  type ColumnDef,
  type RowSelectionState,
} from '@tanstack/react-table';
import { ArrowDown, ArrowUp, ArrowUpDown, Loader2 } from 'lucide-react';

import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from '@/components/ui/table';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { cn } from '@/lib/utils';

export interface DataTablePagination {
  page: number;
  pageSize: number;
  total: number;
  totalPages: number;
}

export interface BulkAction {
  label: string;
  icon?: React.ElementType;
  variant?: 'default' | 'destructive';
  onClick: (selectedIds: string[]) => void;
}

interface DataTableProps<TData> {
  columns: ColumnDef<TData, unknown>[];
  data: TData[];
  pagination?: DataTablePagination;
  onPaginationChange?: (page: number, pageSize: number) => void;
  sort?: { field: string; direction: 'asc' | 'desc' };
  onSortChange?: (field: string, direction: 'asc' | 'desc') => void;
  rowSelection?: RowSelectionState;
  onRowSelectionChange?: (selection: RowSelectionState) => void;
  bulkActions?: BulkAction[];
  emptyState?: React.ReactNode;
  isLoading?: boolean;
  getRowId?: (row: TData) => string;
  onRowClick?: (row: TData) => void;
}

export function DataTable<TData>({
  columns,
  data,
  pagination,
  onPaginationChange,
  sort,
  onSortChange,
  rowSelection: externalSelection,
  onRowSelectionChange,
  bulkActions,
  emptyState,
  isLoading,
  getRowId,
  onRowClick,
}: DataTableProps<TData>) {
  const [internalSelection, setInternalSelection] = useState<RowSelectionState>({});
  const rowSelectionState = externalSelection ?? internalSelection;
  const setRowSelection = onRowSelectionChange ?? setInternalSelection;

  const allColumns: ColumnDef<TData, unknown>[] = [];
  if (bulkActions && bulkActions.length > 0) {
    allColumns.push({
      id: 'select',
      header: ({ table }) => (
        <Checkbox
          checked={
            table.getIsAllPageRowsSelected() ||
            (table.getIsSomePageRowsSelected() && 'indeterminate')
          }
          onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
          aria-label="Select all"
          className="translate-y-[2px]"
        />
      ),
      cell: ({ row }) => (
        <Checkbox
          checked={row.getIsSelected()}
          onCheckedChange={(value) => row.toggleSelected(!!value)}
          aria-label="Select row"
          className="translate-y-[2px]"
          onClick={(e) => e.stopPropagation()}
        />
      ),
      enableSorting: false,
      size: 40,
    });
  }
  allColumns.push(...columns);

  const table = useReactTable({
    data,
    columns: allColumns,
    getCoreRowModel: getCoreRowModel(),
    manualPagination: true,
    manualSorting: true,
    rowCount: pagination?.total ?? data.length,
    state: {
      rowSelection: rowSelectionState,
      pagination: pagination
        ? { pageIndex: pagination.page - 1, pageSize: pagination.pageSize }
        : undefined,
    },
    onRowSelectionChange: (updater) => {
      const newSelection = typeof updater === 'function' ? updater(rowSelectionState) : updater;
      setRowSelection(newSelection);
    },
    getRowId: getRowId as (row: TData, index: number) => string,
    enableRowSelection: !!bulkActions?.length,
  });

  const selectedIds = Object.keys(rowSelectionState).filter((k) => rowSelectionState[k]);

  function handleSort(columnId: string) {
    if (!onSortChange) return;
    if (sort?.field === columnId) {
      onSortChange(columnId, sort.direction === 'asc' ? 'desc' : 'asc');
    } else {
      onSortChange(columnId, 'asc');
    }
  }

  function getSortIcon(columnId: string) {
    if (sort?.field !== columnId) return <ArrowUpDown className="ml-1 h-3.5 w-3.5" />;
    return sort.direction === 'asc' ? (
      <ArrowUp className="ml-1 h-3.5 w-3.5" />
    ) : (
      <ArrowDown className="ml-1 h-3.5 w-3.5" />
    );
  }

  return (
    <div className="space-y-2">
      <div className="rounded-md border overflow-x-auto">
        <Table>
          <TableHeader className="sticky top-0 z-10 bg-muted/50">
            {table.getHeaderGroups().map((headerGroup) => (
              <TableRow key={headerGroup.id}>
                {headerGroup.headers.map((header) => (
                  <TableHead
                    key={header.id}
                    style={{ width: header.getSize() !== 150 ? header.getSize() : undefined }}
                    className={cn(
                      header.column.getCanSort() && onSortChange && 'cursor-pointer select-none',
                    )}
                    onClick={() => {
                      if (
                        header.column.getCanSort() &&
                        onSortChange &&
                        header.column.id !== 'select'
                      ) {
                        handleSort(header.column.id);
                      }
                    }}
                  >
                    <div className="flex items-center">
                      {header.isPlaceholder
                        ? null
                        : flexRender(header.column.columnDef.header, header.getContext())}
                      {header.column.getCanSort() &&
                        onSortChange &&
                        header.column.id !== 'select' &&
                        header.column.id !== 'actions' &&
                        getSortIcon(header.column.id)}
                    </div>
                  </TableHead>
                ))}
              </TableRow>
            ))}
          </TableHeader>
          <TableBody>
            {isLoading ? (
              <TableRow>
                <TableCell colSpan={allColumns.length} className="h-40 text-center">
                  <div className="flex items-center justify-center gap-2">
                    <Loader2 className="h-5 w-5 animate-spin text-muted-foreground" />
                    <span className="text-muted-foreground">Loading...</span>
                  </div>
                </TableCell>
              </TableRow>
            ) : table.getRowModel().rows.length === 0 ? (
              <TableRow>
                <TableCell colSpan={allColumns.length} className="h-40">
                  {emptyState ?? (
                    <div className="text-center text-muted-foreground">No results.</div>
                  )}
                </TableCell>
              </TableRow>
            ) : (
              table.getRowModel().rows.map((row) => (
                <TableRow
                  key={row.id}
                  data-state={row.getIsSelected() && 'selected'}
                  className={cn(onRowClick && 'cursor-pointer')}
                  onClick={() => onRowClick?.(row.original)}
                >
                  {row.getVisibleCells().map((cell) => (
                    <TableCell key={cell.id}>
                      {flexRender(cell.column.columnDef.cell, cell.getContext())}
                    </TableCell>
                  ))}
                </TableRow>
              ))
            )}
          </TableBody>
        </Table>
      </div>

      {/* Pagination */}
      {pagination && pagination.totalPages > 1 && (
        <div className="flex items-center justify-between px-2">
          <div className="text-sm text-muted-foreground">
            {selectedIds.length > 0
              ? `${selectedIds.length} of ${pagination.total} row(s) selected`
              : `${pagination.total} row(s) total`}
          </div>
          <div className="flex items-center gap-2">
            <Button
              variant="outline"
              size="sm"
              disabled={pagination.page <= 1}
              onClick={() => onPaginationChange?.(pagination.page - 1, pagination.pageSize)}
            >
              Previous
            </Button>
            <span className="text-sm text-muted-foreground">
              Page {pagination.page} of {pagination.totalPages}
            </span>
            <Button
              variant="outline"
              size="sm"
              disabled={pagination.page >= pagination.totalPages}
              onClick={() => onPaginationChange?.(pagination.page + 1, pagination.pageSize)}
            >
              Next
            </Button>
          </div>
        </div>
      )}

      {/* Bulk actions bar */}
      {bulkActions && selectedIds.length > 0 && (
        <div className="fixed bottom-6 left-1/2 -translate-x-1/2 z-50 flex items-center gap-3 rounded-lg border bg-background px-4 py-3 shadow-lg animate-in slide-in-from-bottom-4">
          <span className="text-sm font-medium">{selectedIds.length} selected</span>
          {bulkActions.map((action) => (
            <Button
              key={action.label}
              variant={action.variant ?? 'default'}
              size="sm"
              onClick={() => action.onClick(selectedIds)}
            >
              {action.icon && <action.icon className="mr-1.5 h-4 w-4" />}
              {action.label}
            </Button>
          ))}
        </div>
      )}
    </div>
  );
}
