import {
  ColumnDef,
  SortingState,
  VisibilityState,
  flexRender,
  getCoreRowModel,
  getSortedRowModel,
  useReactTable,
} from "@tanstack/react-table"
import * as React from "react"
import { router } from "@inertiajs/react"

// Hook personalizado para debounce
function useDebounce<T>(value: T, delay: number): T {
  const [debouncedValue, setDebouncedValue] = React.useState<T>(value)

  React.useEffect(() => {
    const handler = setTimeout(() => {
      setDebouncedValue(value)
    }, delay)

    return () => {
      clearTimeout(handler)
    }
  }, [value, delay])

  return debouncedValue
}

import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table"
import {
  Pagination,
  PaginationContent,
  PaginationItem,
  PaginationLink,
  PaginationEllipsis,
} from "@/components/ui/pagination"
import { Card, CardContent } from "@/components/ui/card"
import { ChevronDown, ChevronLeft, ChevronRight, Search, Loader2 } from "lucide-react"
import {
  DropdownMenu,
  DropdownMenuCheckboxItem,
  DropdownMenuContent,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select"

// Interfaz para datos paginados de Laravel
export interface PaginatedData<T> {
  data: T[]
  current_page: number
  last_page: number
  per_page: number
  total: number
  from: number | null
  to: number | null
  links?: Array<{
    url: string | null
    label: string
    active: boolean
  }>
}

interface ServerDataTableProps<TData, TValue> {
  columns: ColumnDef<TData, TValue>[]
  paginatedData: PaginatedData<TData>
  searchKey?: string
  searchPlaceholder?: string
  title?: string
  description?: string
  emptyMessage?: string
  renderMobileCard?: (item: TData, index: number) => React.ReactNode
  // Ruta base para las peticiones (ej: "/categories", "/users")
  routeName?: string
  // Filtros adicionales que se deben preservar
  additionalFilters?: Record<string, string | number | boolean | undefined>
  // Valor inicial de búsqueda (desde query string)
  initialSearch?: string
}

export function ServerDataTable<TData, TValue>({
  columns,
  paginatedData,
  searchKey,
  searchPlaceholder = "Buscar...",
  title,
  description,
  emptyMessage = "No se encontraron resultados.",
  renderMobileCard,
  routeName,
  additionalFilters = {},
  initialSearch = "",
}: ServerDataTableProps<TData, TValue>) {
  const [sorting, setSorting] = React.useState<SortingState>([])
  const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})
  const [searchValue, setSearchValue] = React.useState(initialSearch)
  const [isSearching, setIsSearching] = React.useState(false)

  const { data, current_page, last_page, per_page, total, from, to } = paginatedData

  const table = useReactTable({
    data,
    columns,
    onSortingChange: setSorting,
    getCoreRowModel: getCoreRowModel(),
    getSortedRowModel: getSortedRowModel(),
    onColumnVisibilityChange: setColumnVisibility,
    state: {
      sorting,
      columnVisibility,
    },
  })

  // Construir la URL actual para navegación
  const getCurrentUrl = () => {
    if (routeName) return routeName
    // Si no se proporciona routeName, usar la URL actual
    return window.location.pathname
  }

  // Navegar a una página específica
  const goToPage = (page: number) => {
    const url = getCurrentUrl()
    router.get(url, {
      page,
      per_page,
      search: searchValue || undefined,
      ...additionalFilters,
    }, {
      preserveState: true,
      preserveScroll: true,
    })
  }

  // Cambiar cantidad de items por página
  const changePerPage = (newPerPage: number) => {
    const url = getCurrentUrl()
    router.get(url, {
      page: 1, // Reset a la primera página al cambiar per_page
      per_page: newPerPage,
      search: searchValue || undefined,
      ...additionalFilters,
    }, {
      preserveState: true,
      preserveScroll: true,
    })
  }

  // Debounce del valor de búsqueda
  const debouncedSearchValue = useDebounce(searchValue, 300)
  const isFirstMount = React.useRef(true)

  // Efecto para ejecutar búsqueda cuando el valor debounced cambia
  React.useEffect(() => {
    // Evitar ejecutar en el primer mount
    if (isFirstMount.current) {
      isFirstMount.current = false
      return
    }

    const url = getCurrentUrl()
    router.get(url, {
      page: 1,
      per_page,
      search: debouncedSearchValue || undefined,
      ...additionalFilters,
    }, {
      preserveState: true,
      preserveScroll: true,
      onStart: () => setIsSearching(true),
      onFinish: () => setIsSearching(false),
    })
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [debouncedSearchValue])

  // Manejar cambio de búsqueda
  const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value
    setSearchValue(value)
  }

  // Generar números de página para mostrar
  const getPageNumbers = () => {
    const pages: (number | 'ellipsis')[] = []
    const maxVisible = 5

    if (last_page <= maxVisible + 2) {
      // Mostrar todas las páginas si son pocas
      for (let i = 1; i <= last_page; i++) {
        pages.push(i)
      }
    } else {
      // Siempre mostrar la primera página
      pages.push(1)

      if (current_page > 3) {
        pages.push('ellipsis')
      }

      // Páginas alrededor de la actual
      const start = Math.max(2, current_page - 1)
      const end = Math.min(last_page - 1, current_page + 1)

      for (let i = start; i <= end; i++) {
        pages.push(i)
      }

      if (current_page < last_page - 2) {
        pages.push('ellipsis')
      }

      // Siempre mostrar la última página
      if (last_page > 1) {
        pages.push(last_page)
      }
    }

    return pages
  }

  return (
    <div className="w-full">
      {/* Header con filtros - Solo visible en desktop */}
      <div className="hidden md:block">
        {(title || description) && (
          <div className="mb-4">
            {title && <h2 className="text-2xl font-bold tracking-tight">{title}</h2>}
            {description && <p className="text-muted-foreground">{description}</p>}
          </div>
        )}

        <div className="flex items-center justify-between py-4">
          <div className="flex items-center space-x-2">
            {searchKey && (
              <div className="relative">
                <Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
                {isSearching && (
                  <Loader2 className="absolute right-2 top-2.5 h-4 w-4 text-muted-foreground animate-spin" />
                )}
                <Input
                  placeholder={searchPlaceholder}
                  value={searchValue}
                  onChange={handleSearchChange}
                  className="pl-8 pr-8 max-w-sm"
                />
              </div>
            )}
          </div>

          <div className="flex items-center gap-2">
            <DropdownMenu>
              <DropdownMenuTrigger asChild>
                <Button variant="outline" className="ml-auto">
                  Columnas <ChevronDown className="ml-2 h-4 w-4" />
                </Button>
              </DropdownMenuTrigger>
              <DropdownMenuContent align="end">
                {table
                  .getAllColumns()
                  .filter((column) => column.getCanHide())
                  .map((column) => {
                    return (
                      <DropdownMenuCheckboxItem
                        key={column.id}
                        className="capitalize"
                        checked={column.getIsVisible()}
                        onCheckedChange={(value) =>
                          column.toggleVisibility(!!value)
                        }
                      >
                        {column.id}
                      </DropdownMenuCheckboxItem>
                    )
                  })}
              </DropdownMenuContent>
            </DropdownMenu>
          </div>
        </div>

        {/* Tabla para desktop */}
        <div className="rounded-md border">
          <Table>
            <TableHeader>
              {table.getHeaderGroups().map((headerGroup) => (
                <TableRow key={headerGroup.id}>
                  {headerGroup.headers.map((header) => {
                    return (
                      <TableHead key={header.id}>
                        {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}>
                        {flexRender(
                          cell.column.columnDef.cell,
                          cell.getContext()
                        )}
                      </TableCell>
                    ))}
                  </TableRow>
                ))
              ) : (
                <TableRow>
                  <TableCell
                    colSpan={columns.length}
                    className="h-24 text-center"
                  >
                    {emptyMessage}
                  </TableCell>
                </TableRow>
              )}
            </TableBody>
          </Table>
        </div>

        {/* Paginación para desktop */}
        <div className="flex items-center justify-between py-4">
          <div className="text-sm text-muted-foreground">
            {from && to ? (
              <>
                Mostrando {from} a {to} de {total} resultados
              </>
            ) : (
              <>Total: {total} resultados</>
            )}
          </div>

            <div className="flex items-center gap-2">
              <span className="text-sm text-muted-foreground">Mostrar:</span>
              <Select value={per_page.toString()} onValueChange={(v) => changePerPage(Number(v))}>
                <SelectTrigger className="w-[80px]">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="10">10</SelectItem>
                  <SelectItem value="25">25</SelectItem>
                  <SelectItem value="50">50</SelectItem>
                  <SelectItem value="100">100</SelectItem>
                </SelectContent>
              </Select>
            </div>
          
          {last_page > 1 && (
            <Pagination className="mx-0 justify-end">
              <PaginationContent>
                <PaginationItem>
                  <Button
                    variant="ghost"
                    size="sm"
                    onClick={() => goToPage(current_page - 1)}
                    disabled={current_page === 1}
                  >
                    <ChevronLeft className="w-5 h-5" /> Anterior
                  </Button>
                </PaginationItem>

                {getPageNumbers().map((page, index) => (
                  page === 'ellipsis' ? (
                    <PaginationItem key={`ellipsis-${index}`}>
                      <PaginationEllipsis />
                    </PaginationItem>
                  ) : (
                    <PaginationItem key={page}>
                      <PaginationLink
                        onClick={() => goToPage(page)}
                        isActive={current_page === page}
                        className="cursor-pointer"
                      >
                        {page}
                      </PaginationLink>
                    </PaginationItem>
                  )
                ))}

                <PaginationItem>
                  <Button
                    variant="ghost"
                    size="sm"
                    onClick={() => goToPage(current_page + 1)}
                    disabled={current_page === last_page}
                  >
                    Siguiente <ChevronRight />
                  </Button>
                </PaginationItem>
              </PaginationContent>
            </Pagination>
          )}
        </div>
      </div>

      {/* Vista móvil con cards */}
      <div className="block md:hidden">
        {/* Búsqueda móvil */}
        {searchKey && (
          <div className="mb-4">
            <div className="relative">
              <Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
              {isSearching && (
                <Loader2 className="absolute right-2 top-2.5 h-4 w-4 text-muted-foreground animate-spin" />
              )}
              <Input
                placeholder={searchPlaceholder}
                value={searchValue}
                onChange={handleSearchChange}
                className="pl-8 pr-8"
              />
            </div>
          </div>
        )}

        {/* Selector de per_page para móvil */}
        <div className="flex items-center justify-between mb-4">
          <span className="text-sm text-muted-foreground">
            {total} resultados
          </span>
          <Select value={per_page.toString()} onValueChange={(v) => changePerPage(Number(v))}>
            <SelectTrigger className="w-[80px]">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="10">10</SelectItem>
              <SelectItem value="25">25</SelectItem>
              <SelectItem value="50">50</SelectItem>
              <SelectItem value="100">100</SelectItem>
            </SelectContent>
          </Select>
        </div>

        {/* Cards para móvil */}
        <div className="space-y-4">
          {table.getRowModel().rows?.length ? (
            table.getRowModel().rows.map((row, index) => (
              <div key={row.id}>
                {renderMobileCard ? renderMobileCard(row.original, index) : (
                  <Card>
                    <CardContent className="p-4">
                      <div className="space-y-2">
                        {row.getVisibleCells().map((cell) => (
                          <div key={cell.id} className="flex justify-between">
                            <span className="font-medium text-sm text-muted-foreground">
                              {typeof cell.column.columnDef.header === 'string'
                                ? cell.column.columnDef.header
                                : cell.column.id}:
                            </span>
                            <span className="text-sm">
                              {flexRender(
                                cell.column.columnDef.cell,
                                cell.getContext()
                              )}
                            </span>
                          </div>
                        ))}
                      </div>
                    </CardContent>
                  </Card>
                )}
              </div>
            ))
          ) : (
            <Card>
              <CardContent className="p-8 text-center">
                <p className="text-muted-foreground">{emptyMessage}</p>
              </CardContent>
            </Card>
          )}
        </div>

        {/* Paginación móvil */}
        {last_page > 1 && (
          <div className="py-4">
            <div className="flex items-center justify-center mb-2">
              <span className="text-sm text-muted-foreground">
                Página {current_page} de {last_page}
              </span>
            </div>
            <Pagination>
              <PaginationContent>
                <PaginationItem>
                  <Button
                    variant="outline"
                    size="sm"
                    onClick={() => goToPage(current_page - 1)}
                    disabled={current_page === 1}
                  >
                    Anterior
                  </Button>
                </PaginationItem>
                <PaginationItem>
                  <Button
                    variant="outline"
                    size="sm"
                    onClick={() => goToPage(current_page + 1)}
                    disabled={current_page === last_page}
                  >
                    Siguiente
                  </Button>
                </PaginationItem>
              </PaginationContent>
            </Pagination>
          </div>
        )}
      </div>
    </div>
  )
}
