'use client'

import {
  flexRender,
  getCoreRowModel,
  useReactTable,
  type ColumnDef,
  type ColumnSort,
  type RowSelectionState,
  type SortingState,
  type Table,
  type VisibilityState
} from '@tanstack/react-table'
import {
  createContext,
  useContext,
  useEffect,
  useState,
  type ReactNode
} from 'react'
import { useSearchParams } from 'react-router'

import { Card, CardContent } from '@repo/ui/components/ui/card'
import {
  Table as Table_,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow
} from '@repo/ui/components/ui/table'
import { cn } from '@repo/ui/lib/utils'
import { DataTablePagination } from './pagination'

interface DataTableProps<TData, TValue> {
  children?: ReactNode
  columns: ColumnDef<TData, TValue>[]
  data: TData[]
  setSelectedRows?: (selectedRows: TData[]) => void
  pageIndex: number
  sort: SortingState
  pageSize: number
  rowCount: number
  hiddenColumn?: string[]
}

interface TableContextProps<TData> {
  table: Table<TData>
}

const TableContext = createContext<TableContextProps<any> | null>(null)

export function useDataTable<TData>() {
  const ctx = useContext(TableContext)

  if (!ctx) {
    throw new Error('TableContext is null')
  }

  return ctx as { table: Table<TData> }
}

export function DataTable<TData, TValue>({
  data,
  children,
  columns,
  sort,
  pageIndex,
  pageSize,
  rowCount,
  setSelectedRows,
  hiddenColumn = []
}: DataTableProps<TData, TValue>) {
  const [dataTable, setDataTable] = useState<TData[]>(data)
  const columnVisibilityInit = Object.fromEntries(
    hiddenColumn.map((column) => [column, false])
  )
  const [searchParams, setSearchParams] = useSearchParams()
  const [columnVisibility, setColumnVisibility] =
    useState<VisibilityState>(columnVisibilityInit)
  const [rowSelection, setRowSelection] = useState<RowSelectionState>({})
  const sortParam = searchParams.get('sort')
  const sorting = sortParam
    ? sortParam.split(',').map((s) => {
        const [id, dir] = s.split(':')
        return { id, desc: dir === 'desc' }
      })
    : sort

  const setPagination = (updater: any) => {
    const newState =
      typeof updater === 'function' ? updater({ pageIndex, pageSize }) : updater

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

  const setSorting = (updater: any) => {
    const newSorting =
      typeof updater === 'function' ? updater(sorting) : updater

    setSearchParams((searchParams) => {
      if (newSorting.length) {
        const sort = newSorting
          .map((s: ColumnSort) => `${s.id}:${s.desc ? 'desc' : 'asc'}`)
          .join(',')
        searchParams.set('sort', sort)
      }
      return searchParams
    })
  }

  useEffect(() => {
    setDataTable(data)
  }, [data])

  const table = useReactTable({
    data: dataTable,
    columns,
    rowCount,
    state: {
      sorting,
      rowSelection,
      columnVisibility,
      pagination: {
        pageIndex,
        pageSize
      }
    },
    manualSorting: true,
    manualPagination: true,
    enableRowSelection: true,
    getRowId: (row: any) => row.id,
    getCoreRowModel: getCoreRowModel(),
    onRowSelectionChange: setRowSelection,
    onSortingChange: setSorting,
    onColumnVisibilityChange: setColumnVisibility,
    onPaginationChange: setPagination,
    meta: {
      removeRow: (rowId: string) => {
        setDataTable((rows) => rows.filter((row: any) => row?.id !== rowId))
      }
    }
  })

  useEffect(() => {
    const selected = table.getSelectedRowModel().flatRows.map((r) => r.original)
    setSelectedRows?.(selected)
  }, [rowSelection])

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

            <Table_ className="table-auto">
              <TableHeader>
                {table.getHeaderGroups().map((headerGroup) => (
                  <TableRow
                    key={headerGroup.id}
                    className="hover:bg-transparent"
                  >
                    {headerGroup.headers.map((header) => {
                      return (
                        <TableHead
                          key={header.id}
                          className={cn(
                            'p-2.5',
                            // @ts-ignore
                            header.column.columnDef.meta?.className
                          )}
                        >
                          {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={cn(
                            'p-2.5',
                            // @ts-ignore
                            cell.column.columnDef.meta?.className
                          )}
                        >
                          {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>

        <DataTablePagination table={table} />
      </div>
    </TableContext>
  )
}
