'use client'

import {
  flexRender,
  getCoreRowModel,
  useReactTable,
  type ColumnDef,
  type ColumnSort,
  type SortingState,
  type Table,
  type VisibilityState
} from '@tanstack/react-table'
import { createContext, 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 { DataTablePagination } from './pagination'

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

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

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

    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
    })
  }

  // table.getSelectedRowModel().flatRows.map((row) => row.original)

  const table = useReactTable({
    data,
    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
  })

  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-2.5">
                          {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-2.5">
                          {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>
  )
}
