import {
	type ColumnDef,
	type ColumnFiltersState,
	flexRender,
	getCoreRowModel,
	getFilteredRowModel,
	getPaginationRowModel,
	getSortedRowModel,
	type SortingState,
	useReactTable,
	type VisibilityState,
} from "@tanstack/react-table";
import { ChevronLeft, ChevronRight, SlidersHorizontal } from "lucide-react";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import {
	DropdownMenu,
	DropdownMenuCheckboxItem,
	DropdownMenuContent,
	DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { EmptyState } from "@/components/ui/empty-state";
import { Input } from "@/components/ui/input";
import {
	Table,
	TableBody,
	TableCell,
	TableFooter,
	TableHead,
	TableHeader,
	TableRow,
} from "@/components/ui/table";
import { cn } from "@/lib/utils";

/**
 * DataTable component for displaying and managing tabular data
 *
 * @example
 * ```tsx
 * <DataTable
 *   columns={columns}
 *   data={data}
 *   searchKey="title"
 *   emptyState={{
 *     title: "No works found",
 *     description: "Create your first work to get started."
 *   }}
 * />
 * ```
 */

export interface DataTableProps<TData, TValue> {
	/**
	 * Table column definitions
	 */
	columns: ColumnDef<TData, TValue>[];
	/**
	 * Data to display in the table
	 */
	data: TData[];
	/**
	 * Key to use for global search filtering
	 */
	searchKey?: string;
	/**
	 * Total count of items (for server-side pagination)
	 */
	totalCount?: number;
	/**
	 * Whether the table is in a loading state
	 */
	isLoading?: boolean;
	/**
	 * Empty state configuration
	 */
	emptyState?: {
		title: string;
		description?: string;
		action?: React.ReactNode;
	};
	/**
	 * Row click handler
	 */
	onRowClick?: (row: TData) => void;
	/**
	 * Initial page size
	 */
	initialPageSize?: number;
	/**
	 * Show/hide table elements
	 */
	showElements?: {
		search?: boolean;
		pagination?: boolean;
		columnVisibility?: boolean;
	};
	/**
	 * Additional CSS classes
	 */
	className?: string;
}

export function DataTable<TData, TValue>({
	columns,
	data,
	searchKey,
	totalCount,
	isLoading = false,
	emptyState,
	onRowClick,
	initialPageSize = 10,
	showElements = {
		search: true,
		pagination: true,
		columnVisibility: true,
	},
	className,
}: DataTableProps<TData, TValue>) {
	const [sorting, setSorting] = useState<SortingState>([]);
	const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
	const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({});
	const [rowSelection, setRowSelection] = useState({});
	const [globalFilter, setGlobalFilter] = useState("");

	const table = useReactTable({
		data,
		columns,
		getCoreRowModel: getCoreRowModel(),
		getPaginationRowModel: getPaginationRowModel(),
		onSortingChange: setSorting,
		getSortedRowModel: getSortedRowModel(),
		onColumnFiltersChange: setColumnFilters,
		getFilteredRowModel: getFilteredRowModel(),
		onColumnVisibilityChange: setColumnVisibility,
		onRowSelectionChange: setRowSelection,
		onGlobalFilterChange: setGlobalFilter,
		state: {
			sorting,
			columnFilters,
			columnVisibility,
			rowSelection,
			globalFilter,
		},
		initialState: {
			pagination: {
				pageSize: initialPageSize,
			},
		},
	});

	// Handle empty state
	const isEmpty = table.getFilteredRowModel().rows.length === 0;

	return (
		<div className={cn("space-y-4", className)}>
			{/* Table Controls */}
			<div className="flex items-center justify-between gap-2 flex-wrap">
				{/* Search Input */}
				{showElements.search && (
					<div className="flex items-center gap-2">
						<Input
							placeholder={`Search...`}
							value={globalFilter}
							onChange={(e) => setGlobalFilter(e.target.value)}
							className="max-w-xs"
						/>
					</div>
				)}

				{/* View/Filter Options */}
				<div className="flex items-center gap-2 ml-auto">
					{showElements.columnVisibility && (
						<DropdownMenu>
							<DropdownMenuTrigger asChild>
								<Button
									variant="outline"
									size="sm"
									className="ml-auto h-8 gap-1"
								>
									<SlidersHorizontal className="h-4 w-4" />
									<span className="hidden sm:inline">Columns</span>
								</Button>
							</DropdownMenuTrigger>
							<DropdownMenuContent align="end" className="w-[180px]">
								{table
									.getAllColumns()
									.filter((column) => column.getCanHide())
									.map((column) => (
										<DropdownMenuCheckboxItem
											key={column.id}
											className="capitalize"
											checked={column.getIsVisible()}
											onCheckedChange={(value) =>
												column.toggleVisibility(!!value)
											}
										>
											{column.id.replace(/([A-Z])/g, " $1").trim()}
										</DropdownMenuCheckboxItem>
									))}
							</DropdownMenuContent>
						</DropdownMenu>
					)}
				</div>
			</div>

			{/* Table */}
			<div className="rounded-md border">
				<Table>
					<TableHeader>
						{table.getHeaderGroups().map((headerGroup) => (
							<TableRow key={headerGroup.id}>
								{headerGroup.headers.map((header) => (
									<TableHead key={header.id} className="whitespace-nowrap">
										{header.isPlaceholder ? null : (
											<div
												{...{
													className: header.column.getCanSort()
														? "cursor-pointer select-none flex items-center gap-1"
														: "",
													onClick: header.column.getToggleSortingHandler(),
												}}
											>
												{flexRender(
													header.column.columnDef.header,
													header.getContext(),
												)}
												{{
													asc: " 🔼",
													desc: " 🔽",
												}[header.column.getIsSorted() as string] ?? null}
											</div>
										)}
									</TableHead>
								))}
							</TableRow>
						))}
					</TableHeader>
					<TableBody>
						{isLoading ? (
							// Loading state
							Array.from({ length: 5 }).map((_, index) => (
								<TableRow key={index}>
									{columns.map((_, cellIndex) => (
										<TableCell key={cellIndex}>
											<div className="h-4 w-full bg-gray-200 dark:bg-gray-800 animate-pulse rounded" />
										</TableCell>
									))}
								</TableRow>
							))
						) : isEmpty ? (
							// Empty state
							<TableRow>
								<TableCell
									colSpan={columns.length}
									className="h-[300px] text-center"
								>
									{emptyState ? (
										<div className="flex justify-center">
											<EmptyState
												title={emptyState.title}
												description={emptyState.description}
												actions={emptyState.action}
												variant="minimal"
											/>
										</div>
									) : (
										<div className="text-muted-foreground">
											No results found
										</div>
									)}
								</TableCell>
							</TableRow>
						) : (
							// Data rows
							table
								.getRowModel()
								.rows.map((row) => (
									<TableRow
										key={row.id}
										data-state={row.getIsSelected() && "selected"}
										className={cn(
											onRowClick && "cursor-pointer hover:bg-muted",
										)}
										onClick={
											onRowClick ? () => onRowClick(row.original) : undefined
										}
									>
										{row.getVisibleCells().map((cell) => (
											<TableCell key={cell.id}>
												{flexRender(
													cell.column.columnDef.cell,
													cell.getContext(),
												)}
											</TableCell>
										))}
									</TableRow>
								))
						)}
					</TableBody>

					{showElements.pagination && !isEmpty && (
						<TableFooter>
							<TableRow>
								<TableCell colSpan={columns.length}>
									<div className="flex items-center justify-between">
										<div className="text-sm text-muted-foreground">
											Showing{" "}
											<strong>
												{table.getState().pagination.pageIndex *
													table.getState().pagination.pageSize +
													1}
											</strong>{" "}
											to{" "}
											<strong>
												{Math.min(
													(table.getState().pagination.pageIndex + 1) *
														table.getState().pagination.pageSize,
													table.getFilteredRowModel().rows.length,
												)}
											</strong>{" "}
											of{" "}
											<strong>{table.getFilteredRowModel().rows.length}</strong>{" "}
											results
										</div>
										<div className="flex items-center gap-2">
											<Button
												variant="outline"
												size="sm"
												onClick={() => table.previousPage()}
												disabled={!table.getCanPreviousPage()}
											>
												<ChevronLeft className="h-4 w-4" />
											</Button>
											<Button
												variant="outline"
												size="sm"
												onClick={() => table.nextPage()}
												disabled={!table.getCanNextPage()}
											>
												<ChevronRight className="h-4 w-4" />
											</Button>
										</div>
									</div>
								</TableCell>
							</TableRow>
						</TableFooter>
					)}
				</Table>
			</div>
		</div>
	);
}
