"use client"

import { type ReactNode, useMemo, useState } from "react"
import { Search } from "lucide-react"

import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import {
  Pagination,
  PaginationContent,
  PaginationItem,
  PaginationLink,
  PaginationNext,
  PaginationPrevious,
} from "@/components/ui/pagination"
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table"

export interface DataTableColumn<T> {
  key: string
  header: string
  cell: (row: T) => ReactNode
  headerClassName?: string
  cellClassName?: string
}

export interface DataTableFilter<T> {
  key: string
  label: string
  options: string[]
  accessor: (row: T) => string
}

export interface DataTableProps<T> {
  data: readonly T[]
  columns: DataTableColumn<T>[]
  getRowId: (row: T) => string | number
  searchAccessor?: (row: T) => string
  searchPlaceholder?: string
  filters?: DataTableFilter<T>[]
  actions?: (row: T) => ReactNode
  pageSize?: number
  emptyMessage?: string
}

const ALL_VALUE = "All"

export function DataTable<T>({
  data,
  columns,
  getRowId,
  searchAccessor,
  searchPlaceholder = "Search...",
  filters = [],
  actions,
  pageSize = 5,
  emptyMessage = "No results found.",
}: DataTableProps<T>) {
  const [query, setQuery] = useState("")
  const [activeFilters, setActiveFilters] = useState<Record<string, string>>({})
  const [page, setPage] = useState(1)

  const filteredData = useMemo(() => {
    let rows = data

    if (query.trim() && searchAccessor) {
      const q = query.trim().toLowerCase()
      rows = rows.filter((row) => searchAccessor(row).toLowerCase().includes(q))
    }

    for (const filter of filters) {
      const active = activeFilters[filter.key]
      if (active && active !== ALL_VALUE) {
        rows = rows.filter((row) => filter.accessor(row) === active)
      }
    }

    return rows
  }, [data, query, searchAccessor, filters, activeFilters])

  const totalPages = Math.max(1, Math.ceil(filteredData.length / pageSize))
  const currentPage = Math.min(page, totalPages)
  const start = (currentPage - 1) * pageSize
  const visibleRows = filteredData.slice(start, start + pageSize)

  const goTo = (target: number) => setPage(Math.min(Math.max(target, 1), totalPages))

  const setFilter = (key: string, value: string) => {
    setActiveFilters((prev) => ({ ...prev, [key]: value }))
    setPage(1)
  }

  return (
    <div className="flex flex-col gap-4">
      {(searchAccessor || filters.length > 0) && (
        <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
          {searchAccessor && (
            <div className="relative w-full sm:max-w-xs">
              <Search className="pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-slate-400" />
              <Input
                value={query}
                onChange={(e) => {
                  setQuery(e.target.value)
                  setPage(1)
                }}
                placeholder={searchPlaceholder}
                className="h-10 rounded-full bg-slate-50 pl-9"
              />
            </div>
          )}

          {filters.map((filter) => {
            const active = activeFilters[filter.key] ?? ALL_VALUE
            return (
              <div
                key={filter.key}
                className="flex flex-1 flex-wrap items-center gap-2 sm:justify-end"
              >
                {[ALL_VALUE, ...filter.options].map((option) => (
                  <Button
                    key={option}
                    type="button"
                    size="sm"
                    variant={active === option ? "default" : "outline"}
                    className="rounded-full px-4"
                    onClick={() => setFilter(filter.key, option)}
                  >
                    {option}
                  </Button>
                ))}
              </div>
            )
          })}
        </div>
      )}

      <Table>
        <TableHeader>
          <TableRow className="bg-indigo-50 hover:bg-indigo-50">
            {columns.map((column, index) => (
              <TableHead
                key={column.key}
                className={cn(
                  "text-indigo-700",
                  index === 0 && "rounded-l-lg pl-3",
                  index === columns.length - 1 && !actions && "rounded-r-lg pr-3",
                  column.headerClassName
                )}
              >
                {column.header}
              </TableHead>
            ))}
            {actions && (
              <TableHead className="rounded-r-lg pr-3 text-right text-indigo-700">
                Actions
              </TableHead>
            )}
          </TableRow>
        </TableHeader>
        <TableBody>
          {visibleRows.length === 0 && (
            <TableRow>
              <TableCell
                colSpan={columns.length + (actions ? 1 : 0)}
                className="py-8 text-center text-muted-foreground"
              >
                {emptyMessage}
              </TableCell>
            </TableRow>
          )}
          {visibleRows.map((row) => (
            <TableRow key={getRowId(row)}>
              {columns.map((column, index) => (
                <TableCell
                  key={column.key}
                  className={cn(index === 0 && "pl-3", column.cellClassName)}
                >
                  {column.cell(row)}
                </TableCell>
              ))}
              {actions && (
                <TableCell className="pr-3 text-right">{actions(row)}</TableCell>
              )}
            </TableRow>
          ))}
        </TableBody>
      </Table>

      {totalPages > 1 && (
        <Pagination className="justify-between">
          <PaginationContent>
            <PaginationItem>
              <PaginationPrevious
                href="#"
                onClick={(e) => {
                  e.preventDefault()
                  goTo(currentPage - 1)
                }}
                aria-disabled={currentPage === 1}
                className={currentPage === 1 ? "pointer-events-none opacity-50" : undefined}
              />
            </PaginationItem>
          </PaginationContent>

          <PaginationContent>
            {Array.from({ length: totalPages }, (_, i) => i + 1).map((pageNumber) => (
              <PaginationItem key={pageNumber}>
                <PaginationLink
                  href="#"
                  isActive={pageNumber === currentPage}
                  onClick={(e) => {
                    e.preventDefault()
                    goTo(pageNumber)
                  }}
                >
                  {pageNumber}
                </PaginationLink>
              </PaginationItem>
            ))}
          </PaginationContent>

          <PaginationContent>
            <PaginationItem>
              <PaginationNext
                href="#"
                onClick={(e) => {
                  e.preventDefault()
                  goTo(currentPage + 1)
                }}
                aria-disabled={currentPage === totalPages}
                className={
                  currentPage === totalPages ? "pointer-events-none opacity-50" : undefined
                }
              />
            </PaginationItem>
          </PaginationContent>
        </Pagination>
      )}
    </div>
  )
}
