"use client";

import * as React from "react";
import {
	type ColumnDef,
	type OnChangeFn,
	type PaginationState,
	type RowSelectionState,
	type VisibilityState,
	flexRender,
	getCoreRowModel,
	getPaginationRowModel,
	useReactTable,
} from "@tanstack/react-table";
import { Columns3 } from "lucide-react";

import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { TablePagination } from "@/components/ui/table-pagination";
import {
	Table,
	TableBody,
	TableCell,
	TableHead,
	TableHeader,
	TableRow,
} from "@/components/ui/table";
import {
	DropdownMenu,
	DropdownMenuCheckboxItem,
	DropdownMenuContent,
	DropdownMenuLabel,
	DropdownMenuSeparator,
	DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";

export interface DataTableProps<TData, TValue = unknown> {
	columns: ColumnDef<TData, TValue>[];
	data: TData[];
	/** Stable row identity; Media derives it from `path` so selection survives paging. */
	getRowId?: (row: TData, index: number) => string;
	/** Visibility-only feature set (no sorting, no resizing — locked, design §3.3). */
	enableRowSelection?: boolean;
	rowSelection?: RowSelectionState;
	onRowSelectionChange?: OnChangeFn<RowSelectionState>;
	onRowClick?: (row: TData) => void;
	columnVisibility?: VisibilityState;
	onColumnVisibilityChange?: OnChangeFn<VisibilityState>;
	enableColumnVisibilityToggle?: boolean;
	/** Pagination (Media only; FileBrowser does not paginate). */
	enablePagination?: boolean;
	manualPagination?: boolean;
	pagination?: PaginationState;
	onPaginationChange?: OnChangeFn<PaginationState>;
	pageSizeOptions?: number[];
	/** Server total for Media (manual pagination). */
	rowCount?: number;
	emptyMessage?: string;
}

/**
 * Reusable TanStack Table wrapper built on the shadcn `Table` primitive.
 *
 * Visibility-only feature scope (locked, design §3): pagination, row selection,
 * row click, column visibility. A sorting row model is deliberately never
 * wired and column resizing/sizing is never enabled — both are explicit
 * non-goals.
 */
export function DataTable<TData, TValue = unknown>({
	columns,
	data,
	getRowId,
	enableRowSelection = false,
	rowSelection,
	onRowSelectionChange,
	onRowClick,
	columnVisibility,
	onColumnVisibilityChange,
	enableColumnVisibilityToggle = false,
	enablePagination = false,
	manualPagination = false,
	pagination,
	onPaginationChange,
	pageSizeOptions = [10, 20, 30, 50],
	rowCount,
	emptyMessage = "No results.",
}: DataTableProps<TData, TValue>) {
	const pageSize = pagination?.pageSize ?? pageSizeOptions[0] ?? 10;

	// Selection column is a *display* column (no accessor); only rendered when
	// the consumer opts in. Its checkbox handlers stopPropagation so toggling a
	// row never also fires onRowClick navigation.
	const tableColumns = React.useMemo<ColumnDef<TData, TValue>[]>(() => {
		if (!enableRowSelection) return columns;
		const selectColumn: ColumnDef<TData, TValue> = {
			id: "__select__",
			enableSorting: false,
			header: ({ table }) => (
				<Checkbox
					aria-label="Select all rows on this page"
					checked={
						table.getIsAllPageRowsSelected()
							? true
							: table.getIsSomePageRowsSelected()
								? "indeterminate"
								: false
					}
					onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
					onClick={(e) => e.stopPropagation()}
				/>
			),
			cell: ({ row }) => (
				<Checkbox
					aria-label="Select row"
					checked={row.getIsSelected()}
					onCheckedChange={(value) => row.toggleSelected(!!value)}
					onClick={(e) => e.stopPropagation()}
				/>
			),
			enableHiding: false,
		};
		return [selectColumn as ColumnDef<TData, TValue>, ...columns];
	}, [columns, enableRowSelection]);

	/* eslint-disable react-hooks/incompatible-library -- TanStack's
	   useReactTable intentionally returns non-memoizable updater fns (controlled state). */
	const table = useReactTable<TData>({
		data,
		columns: tableColumns,
		getRowId,
		enableRowSelection,
		onRowSelectionChange,
		onColumnVisibilityChange,
		manualPagination: enablePagination ? manualPagination : false,
		rowCount: enablePagination && manualPagination ? rowCount : undefined,
		getCoreRowModel: getCoreRowModel(),
		// Client pagination model ONLY when paginating locally (FileBrowser does
		// not paginate; Media drives the page from the server via limit/offset).
		getPaginationRowModel:
			enablePagination && !manualPagination
				? getPaginationRowModel()
				: undefined,
		state: {
			...(rowSelection !== undefined ? { rowSelection } : {}),
			...(columnVisibility !== undefined ? { columnVisibility } : {}),
			...(enablePagination
				? { pagination: pagination ?? { pageIndex: 0, pageSize } }
				: {}),
		},
		onPaginationChange,
		// Visibility-only: deliberately NO sorting model / sorting state.
	});

	const pageCount =
		enablePagination && rowCount !== undefined && pageSize > 0
			? Math.max(1, Math.ceil(rowCount / pageSize))
			: table.getPageCount();

	return (
		<div className="flex flex-col gap-3">
			<div className="flex items-center justify-end gap-2">
				{enableColumnVisibilityToggle && (
					<DropdownMenu>
						<DropdownMenuTrigger asChild>
							<Button variant="outline" size="sm">
								<Columns3 className="size-4" />
								Columns
							</Button>
						</DropdownMenuTrigger>
						<DropdownMenuContent align="end">
							<DropdownMenuLabel>Toggle columns</DropdownMenuLabel>
							<DropdownMenuSeparator />
							{table
								.getAllColumns()
								.filter((column) => column.getCanHide())
								.map((column) => {
									return (
										<DropdownMenuCheckboxItem
											key={column.id}
											className="capitalize"
											checked={column.getIsVisible()}
											onCheckedChange={(value) =>
												column.toggleVisibility(!!value)
											}
											onSelect={(e) => e.preventDefault()}
										>
											{column.id}
										</DropdownMenuCheckboxItem>
									);
								})}
						</DropdownMenuContent>
					</DropdownMenu>
				)}
			</div>

			<div className="overflow-hidden rounded-lg border">
				<Table>
					<TableHeader>
						{table.getHeaderGroups().map((headerGroup) => (
							<TableRow key={headerGroup.id} className="hover:bg-transparent">
								{headerGroup.headers.map((header) => (
									<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" : undefined}
									className={cn(onRowClick && "cursor-pointer")}
									onClick={() => onRowClick?.(row.original)}
								>
									{row.getVisibleCells().map((cell) => (
										<TableCell key={cell.id}>
											{flexRender(
												cell.column.columnDef.cell,
												cell.getContext(),
											)}
										</TableCell>
									))}
								</TableRow>
							))
						) : (
							<TableRow className="hover:bg-transparent">
								<TableCell
									colSpan={tableColumns.length}
									className="h-24 text-center text-muted-foreground"
								>
									{emptyMessage}
								</TableCell>
							</TableRow>
						)}
					</TableBody>
				</Table>
			</div>

			{enablePagination && (
				<TablePagination
					pageIndex={table.getState().pagination.pageIndex}
					pageSize={table.getState().pagination.pageSize}
					pageSizeOptions={pageSizeOptions}
					totalRows={manualPagination ? (rowCount ?? 0) : table.getRowModel().rows.length}
					pageCount={pageCount}
					onPaginationChange={table.setPagination}
				/>
			)}
		</div>
	);
}

// DataTablePagination was extracted into the shared TablePagination component
// (frontend/src/components/ui/table-pagination.tsx). Both the desktop DataTable
// and the Media mobile card list consume it.
