"use client"

import {
  flexRender,
  getCoreRowModel,
  getFilteredRowModel,
  getPaginationRowModel,
  getSortedRowModel,
  useReactTable,
  type ColumnDef,
  type ColumnFiltersState,
  type PaginationState,
  type SortingState,
} from "@tanstack/react-table"
import { Link } from "@/i18n/navigation"
import { useTranslations } from "next-intl"

import { DataTableColumnHeader } from "@/components/data-table-column-header"
import { DataTablePagination } from "@/components/data-table-pagination"
import { Button } from "@/components/ui/button"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { Skeleton } from "@/components/ui/skeleton"
import { Input } from "@/components/ui/input"
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table"
import type { LucideIcon } from "lucide-react"
import { EllipsisVerticalIcon, Loader2Icon, XIcon } from "lucide-react"
import { useEffect, useMemo, useRef, useState } from "react"

export type SuperRowAction<TData> =
  | {
      type: "link"
      label: string
      href: (row: TData) => string
      icon?: LucideIcon
    }
  | {
      type: "action"
      label: string
      onClick: (row: TData) => void
      destructive?: boolean
      icon?: LucideIcon
    }
  | { type: "separator" }

export type ServerPageStatus = {
  current: number
  last: number
  total: number
}

export type SuperDataTableServerPagination = {
  page: number
  lastPage: number
  perPage: number
  onPageChange: (page: number) => void
  onPerPageChange: (perPage: number) => void
  disabled?: boolean
  perPageOptions?: readonly number[]
  showRowsPerPage?: boolean
}

const DEFAULT_PAGE_SIZE = 15
const SEARCH_DEBOUNCE_MS = 600
const MIN_CLIENT_SEARCH_LENGTH = 3

function SearchInputWithClear({
  value,
  onChange,
  placeholder,
  ariaLabel,
  isLoading,
}: {
  value: string
  onChange: (value: string) => void
  placeholder?: string
  ariaLabel?: string
  isLoading?: boolean
}) {
  const tc = useTranslations("Common")

  return (
    <div className="relative w-full max-w-sm">
      <Input
        value={value}
        onChange={(e) => onChange(e.target.value)}
        placeholder={placeholder}
        aria-label={ariaLabel ?? placeholder}
        className="pr-9 h-9"
      />
      {isLoading ? (
        <Loader2Icon
          className="top-1/2 right-2.5 absolute size-4 text-muted-foreground -translate-y-1/2 animate-spin"
          aria-hidden
        />
      ) : value.trim().length ? (
        <Button
          type="button"
          variant="ghost"
          size="icon-sm"
          className="top-1/2 right-1 absolute text-muted-foreground -translate-y-1/2"
          aria-label={tc("table.clearSearch")}
          onClick={() => onChange("")}
        >
          <XIcon className="size-4" aria-hidden />
        </Button>
      ) : null}
    </div>
  )
}

export function SuperDataTable<TData>({
  data,
  columns,
  searchKey,
  searchPlaceholder = "Search…",
  serverSearch,
  pageStatus,
  pageStatusCountLabel = "total",
  serverPagination,
  actionsForRow,
  disableClientPagination = false,
  loading = false,
  skeletonRowCount = 8,
  defaultSearch = "",
  onSearch,
}: {
  data: TData[]
  columns: ColumnDef<TData>[]
  searchKey?: string
  searchPlaceholder?: string
  serverSearch?: {
    value: string
    onChange: (value: string) => void
    placeholder?: string
    ariaLabel?: string
  }
  pageStatus?: ServerPageStatus
  pageStatusCountLabel?: "total" | "logs"
  serverPagination?: SuperDataTableServerPagination
  actionsForRow?: (row: TData) => SuperRowAction<TData>[]
  disableClientPagination?: boolean
  loading?: boolean
  skeletonRowCount?: number
  /** Pre-populate the client-side search input (e.g. from URL param). */
  defaultSearch?: string
  /** Called with the debounced search value whenever it changes (use to sync URL). */
  onSearch?: (value: string) => void
}) {
  const tc = useTranslations("Common")
  const [searchInput, setSearchInput] = useState(defaultSearch)
  const [debouncedSearch, setDebouncedSearch] = useState(defaultSearch)
  const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
  const [sorting, setSorting] = useState<SortingState>([])
  const [pagination, setPagination] = useState<PaginationState>({
    pageIndex: 0,
    pageSize: DEFAULT_PAGE_SIZE,
  })

  const cols = useMemo<ColumnDef<TData>[]>(
    () => [
      ...columns,
      ...(actionsForRow
        ? [
            {
              id: "actions",
              header: "",
              cell: ({ row }) => {
                const actions = actionsForRow(row.original)
                return (
                  <DropdownMenu>
                    <DropdownMenuTrigger asChild>
                      <Button variant="ghost" size="icon" className="size-8">
                        <EllipsisVerticalIcon />
                        <span className="sr-only">{tc("table.openMenu")}</span>
                      </Button>
                    </DropdownMenuTrigger>
                    <DropdownMenuContent align="end" className="w-52">
                      {actions.map((a, idx) => {
                        if (a.type === "separator") {
                          return <DropdownMenuSeparator key={idx} />
                        }

                        const Icon = a.icon

                        if (a.type === "link") {
                          return (
                            <DropdownMenuItem key={idx} asChild>
                              <Link href={a.href(row.original)}>
                                {Icon ? <Icon className="size-4" /> : null}
                                {a.label}
                              </Link>
                            </DropdownMenuItem>
                          )
                        }

                        return (
                          <DropdownMenuItem
                            key={idx}
                            variant={a.destructive ? "destructive" : undefined}
                            onClick={() => a.onClick(row.original)}
                          >
                            {Icon ? <Icon className="size-4" /> : null}
                            {a.label}
                          </DropdownMenuItem>
                        )
                      })}
                    </DropdownMenuContent>
                  </DropdownMenu>
                )
              },
              enableSorting: false,
            } as ColumnDef<TData>,
          ]
        : []),
    ],
    [columns, actionsForRow, tc]
  )

  const table = useReactTable({
    data,
    columns: cols,
    state: {
      columnFilters,
      sorting,
      ...(disableClientPagination ? {} : { pagination }),
    },
    onColumnFiltersChange: setColumnFilters,
    onSortingChange: setSorting,
    ...(disableClientPagination ? {} : { onPaginationChange: setPagination }),
    getCoreRowModel: getCoreRowModel(),
    getFilteredRowModel: getFilteredRowModel(),
    getSortedRowModel: getSortedRowModel(),
    ...(disableClientPagination ? {} : { getPaginationRowModel: getPaginationRowModel() }),
  })

  const onSearchRef = useRef(onSearch)
  onSearchRef.current = onSearch
  const lastEmittedSearchRef = useRef<string | null>(null)

  useEffect(() => {
    const handle = window.setTimeout(() => {
      const trimmed = searchInput.trim()
      const next =
        trimmed.length === 0 || trimmed.length >= MIN_CLIENT_SEARCH_LENGTH
          ? trimmed
          : ""
      setDebouncedSearch(next)
      // Avoid URL sync loops: inline onSearch identities change every render.
      if (lastEmittedSearchRef.current === next) return
      lastEmittedSearchRef.current = next
      onSearchRef.current?.(next)
    }, SEARCH_DEBOUNCE_MS)
    return () => window.clearTimeout(handle)
  }, [searchInput])

  useEffect(() => {
    if (!searchKey) return
    table.getColumn(searchKey)?.setFilterValue(debouncedSearch)
  }, [debouncedSearch, searchKey, table])

  const pageStatusKey =
    pageStatusCountLabel === "logs"
      ? "table.pageStatusLogs"
      : "table.pageStatus"

  const resolvedPageStatus: ServerPageStatus =
    pageStatus ??
    (disableClientPagination
      ? {
          current: serverPagination?.page ?? 1,
          last: Math.max(1, serverPagination?.lastPage ?? 1),
          total: data.length,
        }
      : {
          current: pagination.pageIndex + 1,
          last: Math.max(1, table.getPageCount()),
          total: table.getFilteredRowModel().rows.length,
        })

  return (
    <div className="gap-3 grid px-4 lg:px-6">
      <div className="flex sm:flex-row flex-col sm:justify-between sm:items-center gap-3">
        {serverSearch ? (
          <SearchInputWithClear
            value={serverSearch.value}
            onChange={serverSearch.onChange}
            placeholder={serverSearch.placeholder ?? searchPlaceholder}
            ariaLabel={serverSearch.ariaLabel ?? serverSearch.placeholder}
            isLoading={loading}
          />
        ) : searchKey ? (
          <SearchInputWithClear
            value={searchInput}
            onChange={setSearchInput}
            placeholder={searchPlaceholder}
            isLoading={loading}
          />
        ) : (
          <div />
        )}
        <p className="text-muted-foreground text-sm whitespace-nowrap">
          {tc(pageStatusKey, resolvedPageStatus)}
        </p>
      </div>

      <div className="border rounded-lg overflow-hidden">
        <Table>
          <TableHeader className="bg-muted">
            {table.getHeaderGroups().map((hg) => (
              <TableRow key={hg.id}>
                {hg.headers.map((header) => {
                  const columnDef = header.column.columnDef
                  const headerContent =
                    header.isPlaceholder ? null : typeof columnDef.header ===
                      "string" && header.column.getCanSort() ? (
                      <DataTableColumnHeader
                        column={header.column}
                        title={columnDef.header}
                      />
                    ) : (
                      flexRender(columnDef.header, header.getContext())
                    )

                  return <TableHead key={header.id}>{headerContent}</TableHead>
                })}
              </TableRow>
            ))}
          </TableHeader>
          <TableBody>
            {loading ? (
              Array.from({ length: skeletonRowCount }).map((_, i) => (
                <TableRow key={i}>
                  <TableCell colSpan={cols.length} className="py-2">
                    <Skeleton className="w-full h-8" />
                  </TableCell>
                </TableRow>
              ))
            ) : table.getRowModel().rows.length ? (
              table.getRowModel().rows.map((row) => (
                <TableRow key={row.id}>
                  {row.getVisibleCells().map((cell) => (
                    <TableCell key={cell.id}>
                      {flexRender(cell.column.columnDef.cell, cell.getContext())}
                    </TableCell>
                  ))}
                </TableRow>
              ))
            ) : (
              <TableRow>
                <TableCell colSpan={cols.length} className="h-24 text-center">
                  {tc("table.noResults")}
                </TableCell>
              </TableRow>
            )}
          </TableBody>
        </Table>
      </div>

      {disableClientPagination && serverPagination ? (
        <DataTablePagination {...serverPagination} />
      ) : disableClientPagination ? null : (
        <DataTablePagination
          page={pagination.pageIndex + 1}
          lastPage={Math.max(1, table.getPageCount())}
          perPage={pagination.pageSize}
          onPageChange={(nextPage) => table.setPageIndex(nextPage - 1)}
          onPerPageChange={(nextPerPage) => {
            table.setPageSize(nextPerPage)
            table.setPageIndex(0)
          }}
        />
      )}
    </div>
  )
}
