import {
	type ColumnDef,
	type ColumnFiltersState,
	type ColumnSort,
	flexRender,
	getCoreRowModel,
	getFilteredRowModel,
	getPaginationRowModel,
	getSortedRowModel,
	type RowSelectionState,
	type SortingState,
	type Table as TableType,
	useReactTable,
	type VisibilityState,
} from "@tanstack/react-table";
import { useVirtualizer } from "@tanstack/react-virtual";
import { useEffect, useRef, useState } from "react";
import { DataTablePagination } from "~/components/custom_ui/dataTable-pagination";
import {
	DataTableToolbar,
	type PinnedFiltro,
	type SearchFiltro,
} from "~/components/custom_ui/dataTable-toolbar";
import {
	Table,
	TableBody,
	TableCell,
	TableHead,
	TableHeader,
	TableRow,
} from "~/components/ui/table";
import { cn } from "~/lib/utils";

interface DataTableProps<TData, TValue> {
	columns: ColumnDef<TData, TValue>[];
	data: TData[];
	pinnedFiltri?: PinnedFiltro[];
	hasSelectRow?: boolean;
	searchColumn?: SearchFiltro;
	columns_titles: Record<string, string>;
	defaultSort?: ColumnSort[];
	rowOnClick?: (data: TData, rowId: string) => void;
	highlightedRow?: string;
	defaultColumnVisibility?: VisibilityState;
	tabClassName?: string;
	pagination?: boolean;
	onStateChange?: () => void;
	defaultFilterState?: ColumnFiltersState;
	onTableInit?: (table: TableType<TData>) => void;
}

export function DataTable<TData, TValue>({
	columns,
	data,
	pinnedFiltri,
	hasSelectRow,
	searchColumn,
	columns_titles,
	defaultSort,
	rowOnClick,
	highlightedRow,
	defaultColumnVisibility,
	tabClassName,
	pagination = true,
	onStateChange,
	defaultFilterState,
	onTableInit,
}: DataTableProps<TData, TValue>) {
	const [sorting, setSorting] = useState<SortingState>(defaultSort || []);
	const [rowSelection, setRowSelection] = useState<RowSelectionState>({});

	const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>(
		defaultFilterState || [],
	);
	const [columnVisibility, setColumnVisibility] = useState<VisibilityState>(
		defaultColumnVisibility || {},
	);

	const [globalFilter, setGlobalFilter] = useState<string>("");

	useEffect(() => {
		onStateChange?.();
	}, [rowSelection, columnFilters, columnVisibility, sorting, onStateChange]);

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

	const parentRef = useRef<HTMLDivElement>(null);
	const { rows } = table.getRowModel();
	const virtualizer = useVirtualizer({
		count: rows.length,
		estimateSize: () => 34,
		getScrollElement: () => parentRef.current,
		overscan: 20,
	});

	useEffect(() => {
		if (table && onTableInit) {
			onTableInit(table);
		}
	}, [table, onTableInit]);

	return (
		<div className="space-y-4">
			<DataTableToolbar
				columns_titles={columns_titles}
				globalFilter={globalFilter}
				pinnedColumns={pinnedFiltri}
				searchColumn={searchColumn}
				table={table}
			/>
			<div className="rounded-md border" ref={parentRef}>
				<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 className={tabClassName}>
						{virtualizer.getVirtualItems().length ? (
							virtualizer.getVirtualItems().map((virtualRow, index) => {
								// biome-ignore lint/style/noNonNullAssertion: <always exists>
								const row = rows[virtualRow.index]!;
								return (
									<TableRow
										className={cn(
											rowOnClick && "cursor-pointer",
											highlightedRow === row.id && "bg-neutral-100/50",
											"group/row",
										)}
										data-row-id={row.id}
										data-state={row.getIsSelected() && "selected"}
										key={row.id}
										onClick={
											rowOnClick
												? () => rowOnClick(row.original, row.id)
												: undefined
										}
										style={{
											height: `${virtualRow.size}px`,
											transform: `translateY(${
												virtualRow.start - index * virtualRow.size
											}px)`,
										}}
									>
										{row.getVisibleCells().map((cell) => {
											return (
												<TableCell key={cell.id}>
													{flexRender(
														cell.column.columnDef.cell,
														cell.getContext(),
													)}
												</TableCell>
											);
										})}
									</TableRow>
								);
							})
						) : (
							<TableRow>
								<TableCell
									className="h-24 text-center"
									colSpan={columns.length}
								>
									No results.
								</TableCell>
							</TableRow>
						)}
					</TableBody>
				</Table>
			</div>
			{pagination ? (
				<DataTablePagination hasSelectRow={hasSelectRow} table={table} />
			) : null}
		</div>
	);
}
