'use client'

import {
  flexRender,
  getCoreRowModel,
  useReactTable,
  type ColumnDef,
  type Table as TTable,
  type VisibilityState
} from '@tanstack/react-table'
import {
  ChevronDownIcon,
  ChevronLeftIcon,
  ChevronRightIcon,
  Columns2Icon
} from 'lucide-react'
import { createContext, useContext, useState, type ReactNode } from 'react'
import { useSearchParams } from 'react-router'

import { Button } from '@repo/ui/components/ui/button'
import { Card, CardContent } from '@repo/ui/components/ui/card'
import {
  DropdownMenu,
  DropdownMenuCheckboxItem,
  DropdownMenuContent,
  DropdownMenuTrigger
} from '@repo/ui/components/ui/dropdown-menu'
import { Label } from '@repo/ui/components/ui/label'
import {
  Pagination,
  PaginationContent,
  PaginationItem
} from '@repo/ui/components/ui/pagination'
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue
} from '@repo/ui/components/ui/select'
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow
} from '@repo/ui/components/ui/table'
import { cn } from '@repo/ui/lib/utils'

interface DataTableProps<TData, TValue> {
  children?: ReactNode
  columns: ColumnDef<TData, TValue>[]
  data: TData[]
  pageIndex: number
  pageSize: number
  rowCount: number
  hiddenColumn?: string[]
}

const TableContext = createContext<{ table: TTable<any> } | null>(null)

export function DataTable<TData, TValue>({
  children,
  columns,
  data,
  pageIndex,
  pageSize,
  rowCount,
  hiddenColumn = []
}: DataTableProps<TData, TValue>) {
  const [, setSearchParams] = useSearchParams()
  const hiddenColumn_ = Object.fromEntries(
    hiddenColumn.map((column) => [column, false])
  )
  const [columnVisibility, setColumnVisibility] =
    useState<VisibilityState>(hiddenColumn_)
  const [rowSelection, setRowSelection] = useState({})

  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
    onRowSelectionChange: setRowSelection,
    state: {
      rowSelection,
      columnVisibility,
      pagination: {
        pageIndex,
        pageSize
      }
    },
    onColumnVisibilityChange: setColumnVisibility,
    onPaginationChange: (updater) => {
      const newState =
        typeof updater === 'function'
          ? updater({ pageIndex, pageSize })
          : updater

      setSearchParams((searchParams) => {
        searchParams.set('p', newState?.pageIndex.toString())
        searchParams.set('perPage', newState?.pageSize.toString())
        return searchParams
      })
    },
    manualPagination: true,
    rowCount
  })

  return (
    <TableContext value={{ table }}>
      <div className="space-y-2.5 max-md:mb-2">
        <Card className="relative w-full overflow-auto">
          <CardContent>
            {children}

            <Table>
              <TableHeader>
                {table.getHeaderGroups().map((headerGroup) => (
                  <TableRow
                    key={headerGroup.id}
                    className="hover:bg-transparent"
                  >
                    {headerGroup.headers.map((header) => {
                      return (
                        <TableHead key={header.id} className="p-4">
                          {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'}
                    >
                      {row.getVisibleCells().map((cell) => (
                        <TableCell key={cell.id} className="p-4">
                          {flexRender(
                            cell.column.columnDef.cell,
                            cell.getContext()
                          )}
                        </TableCell>
                      ))}
                    </TableRow>
                  ))
                ) : (
                  <TableRow>
                    <TableCell
                      colSpan={columns.length}
                      className="h-24 text-center"
                    >
                      Nenhum resultado.
                    </TableCell>
                  </TableRow>
                )}
              </TableBody>
            </Table>
          </CardContent>
        </Card>

        <div className="flex items-center justify-end gap-5">
          <div className="hidden items-center gap-2.5 lg:flex">
            <Label htmlFor="rows-per-page" className="text-sm font-medium">
              Itens por página
            </Label>
            <Select
              value={String(table.getState().pagination.pageSize)}
              onValueChange={(value) => {
                table.setPageSize(Number(value))
              }}
            >
              <SelectTrigger size="sm" className="w-20">
                <SelectValue
                  placeholder={String(table.getState().pagination.pageSize)}
                />
              </SelectTrigger>
              <SelectContent side="top">
                {[12, 25, 50, 100].map((pageSize) => (
                  <SelectItem key={pageSize} value={String(pageSize)}>
                    {pageSize}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>

          <div className="flex items-center gap-5">
            <Pagination>
              <PaginationContent className="gap-2">
                <PaginationItem>
                  {(pageIndex + 1) * pageSize - pageSize + 1}-
                  {Math.min((pageIndex + 1) * pageSize, rowCount)}
                </PaginationItem>

                <PaginationItem>
                  <Button
                    variant="ghost"
                    className="cursor-pointer"
                    onClick={() => table.previousPage()}
                    disabled={!table.getCanPreviousPage()}
                  >
                    <ChevronLeftIcon />
                  </Button>
                </PaginationItem>

                <PaginationItem>
                  <Button
                    variant="ghost"
                    className="cursor-pointer"
                    onClick={() => table.nextPage()}
                    disabled={!table.getCanNextPage()}
                  >
                    <ChevronRightIcon />
                  </Button>
                </PaginationItem>
              </PaginationContent>
            </Pagination>
          </div>
        </div>
      </div>
    </TableContext>
  )
}

export function CustomizeColumns({ className }: { className?: string }) {
  const { table } = useContext(TableContext)

  return (
    <DropdownMenu>
      <DropdownMenuTrigger asChild>
        <Button variant="outline" className={cn('cursor-pointer', className)}>
          <Columns2Icon />
          <span className="hidden lg:inline">Exibir colunas</span>
          <span className="lg:hidden">Colunas</span>
          <ChevronDownIcon />
        </Button>
      </DropdownMenuTrigger>
      <DropdownMenuContent align="end" className="w-56 *:cursor-pointer">
        {table
          .getAllColumns()
          .filter(
            (column) =>
              typeof column.accessorFn !== 'undefined' && column.getCanHide()
          )
          .map((column) => {
            return (
              <DropdownMenuCheckboxItem
                key={column.id}
                checked={column.getIsVisible()}
                onCheckedChange={(value) => column.toggleVisibility(!!value)}
              >
                {column.columnDef.header}
              </DropdownMenuCheckboxItem>
            )
          })}
      </DropdownMenuContent>
    </DropdownMenu>
  )
}
