import * as React from 'react';
import {
	ColumnDef,
	ColumnFiltersState,
	SortingState,
	VisibilityState,
	flexRender,
	getCoreRowModel,
	getFilteredRowModel,
	getPaginationRowModel,
	useReactTable,
} from '@tanstack/react-table';
import {
	ArrowUpDown,
	ArrowUp,
	ArrowDown,
	Search,
	Settings,
	Filter,
	PlusCircle,
	Trash2,
	SquarePen,
	Eye,
} from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import {
	DropdownMenu,
	DropdownMenuCheckboxItem,
	DropdownMenuContent,
	DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { Input } from '@/components/ui/input';
import {
	Table,
	TableBody,
	TableCell,
	TableHead,
	TableHeader,
	TableRow,
} from '@/components/ui/table';
import { renderPageNumbers } from './Pagination';
import Link from 'next/link';
import { DataGridProps } from '@/types/table';
import { TableItemPerPageList } from '@/constant/table';

export function BasicDataGrid<T>({
	data,
	columns,
	title,
	searchPlaceholder = 'Search...',
	showSearch = true,
	showColumnSelector = true,
	showPagination = true,
	showRowSelection = false,
	currentPage = 1,
	totalPages = 1,
	itemsPerPage = 10,
	onItemPerPageChange,
	onPageChange,
	onSearch,
	rowClickPath,
	onRowSelectionChange,
	onFilterClick,
	showFilter = false,
	onAddClick,
	showAddButton = false,
	buttonTitle = 'Add',
	showActions = true,
	onView,
	onEdit,
	onDelete,
	customButtons,
	onSortChange,
	initialSort,
	initialSearchValue,
	showItemsPerPage = false,
}: DataGridProps<T>) {
	const [itemsPerPageState, setItemsPerPageState] =
		React.useState(itemsPerPage);
	const randomNum = React.useRef(Math.floor(Math.random() * 1000) + 1);
	const [sorting, setSorting] = React.useState<SortingState>(
		initialSort ? [{ id: initialSort.id, desc: initialSort.desc }] : []
	);
	const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
		[]
	);
	const [columnVisibility, setColumnVisibility] =
		React.useState<VisibilityState>({});
	const [rowSelection, setRowSelection] = React.useState({});
	const [globalFilter, setGlobalFilter] = React.useState('');
	const [searchQuery, setSearchQuery] = React.useState(
		initialSearchValue ?? ''
	);

	const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
		const value = e.target.value;
		setSearchQuery(value);
		if (onSearch) {
			onSearch(value);
			return;
		}
		setGlobalFilter(value);
	};

	const handleItemsPerPageChange = (value: number) => {
		setItemsPerPageState(value);
		if (onItemPerPageChange) {
			onItemPerPageChange(value);
		}
		if (onPageChange) {
			onPageChange(1);
		}
	};

	const tanstackColumns = React.useMemo<ColumnDef<T>[]>(() => {
		const result: ColumnDef<T>[] = [];

		if (showRowSelection) {
			result.push({
				id: 'select',
				sortingFn: 'textCaseSensitive',
				header: ({ table }) => (
					<Checkbox
						checked={
							table.getIsAllPageRowsSelected() ||
							(table.getIsSomePageRowsSelected()
								? 'indeterminate'
								: false)
						}
						onCheckedChange={(value) =>
							table.toggleAllPageRowsSelected(!!value)
						}
						aria-label="Select all"
						className="border-[#CBB26A]/30 data-[state=checked]:bg-[#CBB26A] data-[state=checked]:border-[#CBB26A]"
					/>
				),
				cell: ({ row }) => (
					<Checkbox
						checked={row.getIsSelected()}
						onCheckedChange={(value) => row.toggleSelected(!!value)}
						aria-label="Select row"
						className="border-[#CBB26A]/30 data-[state=checked]:bg-[#CBB26A] data-[state=checked]:border-[#CBB26A]"
					/>
				),
				enableSorting: false,
				enableHiding: false,
			});
		}

		columns.forEach((column) => {
			result.push({
				id: column.id,
				sortingFn: 'textCaseSensitive',
				accessorKey: column.accessorKey as string,
				header: ({ column: col }) => {
					if (!column.sortable) {
						return (
							<span className="text-[#CBB26A]/80 font-medium tracking-wide text-xs uppercase">
								{column.header}
							</span>
						);
					}
					return (
						<Button
							variant="ghost"
							onClick={() => {
								const isSorted = col.getIsSorted();
								let newSort: { id: string; desc: boolean } | null =
									null;

								if (isSorted === 'asc') {
									newSort = { id: column.id, desc: true };
								} else if (isSorted === 'desc') {
									newSort = null;
								} else {
									newSort = { id: column.id, desc: false };
								}

								setSorting(
									newSort
										? [{ id: newSort.id, desc: newSort.desc }]
										: []
								);

								if (onSortChange) {
									onSortChange(newSort);
								}
							}}
							className={`px-2 hover:bg-[#CBB26A]/10 h-7 ${
								col.getIsSorted()
									? 'text-[#CBB26A]'
									: 'text-[#CBB26A]/70'
							}`}
						>
							<span className="font-medium tracking-wide text-xs uppercase">
								{column.header}
							</span>
							{col.getIsSorted() === 'asc' ? (
								<ArrowUp className="ml-1.5 h-3 w-3 text-[#CBB26A]" />
							) : col.getIsSorted() === 'desc' ? (
								<ArrowDown className="ml-1.5 h-3 w-3 text-[#CBB26A]" />
							) : (
								<ArrowUpDown className="ml-1.5 h-3 w-3 text-[#CBB26A]/40" />
							)}
						</Button>
					);
				},
				cell: ({ row }) => {
					if (column.cell) {
						return column.cell(row.original);
					}
					if (rowClickPath && column.id === 'name') {
						return (
							<Link
								href={rowClickPath(row.original)}
								className="text-[#CBB26A] hover:text-[#CBB26A]/80 hover:underline transition-colors duration-200 text-sm"
							>
								{String(row.getValue(column.id))}
							</Link>
						);
					}
					return (
						<div className="text-sm text-[#E5D9C6]/90">
							{String(row.getValue(column.id))}
						</div>
					);
				},
				enableSorting: column.sortable,
				enableHiding: column.filterable,
			});
		});

		if (showActions) {
			result.push({
				id: `actions-sample-${randomNum.current}`,
				header: () => (
					<span className="text-[#CBB26A]/80 font-medium tracking-wide text-xs uppercase">
						Actions
					</span>
				),
				enableHiding: false,
				enableSorting: true,
				cell: ({ row }) => (
					<div className="flex gap-1.5">
						{onEdit && (
							<Button
								size="icon"
								variant="ghost"
								className="h-7 w-7 hover:bg-[#CBB26A]/10 text-[#E5D9C6]/70 hover:text-[#CBB26A] transition-all duration-200"
								onClick={() => onEdit(row.original)}
							>
								<SquarePen className="h-3.5 w-3.5" />
								<span className="sr-only">Edit</span>
							</Button>
						)}
						{onDelete && (
							<Button
								size="icon"
								variant="ghost"
								className="h-7 w-7 hover:bg-destructive/10 text-[#E5D9C6]/70 hover:text-destructive transition-all duration-200"
								onClick={() => onDelete(row.original)}
							>
								<Trash2 className="h-3.5 w-3.5" />
								<span className="sr-only">Delete</span>
							</Button>
						)}
						{onView && (
							<Button
								size="icon"
								variant="ghost"
								className="h-7 w-7 hover:bg-destructive/10 text-[#E5D9C6]/70 hover:text-destructive transition-all duration-200"
								onClick={() => onView(row.original)}
							>
								<Eye className="h-3.5 w-3.5" />
								<span className="sr-only">Detail</span>
							</Button>
						)}
					</div>
				),
			});
		}

		return result;
	}, [
		columns,
		showRowSelection,
		rowClickPath,
		showActions,
		onView,
		onEdit,
		onDelete,
		onSortChange,
	]);

	const table = useReactTable({
		data,
		columns: tanstackColumns,
		initialState: {
			pagination: {
				pageSize: itemsPerPage,
			},
			sorting: initialSort
				? [{ id: initialSort.id, desc: initialSort.desc }]
				: [],
		},
		onSortingChange: setSorting,
		onColumnFiltersChange: setColumnFilters,
		...(onSearch ? {} : { onGlobalFilterChange: setGlobalFilter }),
		getCoreRowModel: getCoreRowModel(),
		getPaginationRowModel: getPaginationRowModel(),
		...(onSearch ? {} : { getFilteredRowModel: getFilteredRowModel() }),
		onColumnVisibilityChange: setColumnVisibility,
		onRowSelectionChange: setRowSelection,
		state: {
			sorting,
			columnFilters,
			columnVisibility,
			rowSelection,
			...(onSearch ? {} : { globalFilter }),
		},
		manualSorting: true,
	});

	React.useEffect(() => {
		if (onRowSelectionChange) {
			const selectedRows = table
				.getSelectedRowModel()
				.flatRows.map((row) => row.original);
			onRowSelectionChange(selectedRows);
		}
	}, []);

	const handlePageChange = (page: number) => {
		if (onPageChange) {
			onPageChange(page);
		} else {
			table.setPageIndex(page - 1);
		}
	};

	return (
		<div className="space-y-6 w-full mx-auto">
			{title && (
				<div className="flex items-center justify-between">
					<div className="relative">
						<h2 className="text-2xl font-serif font-bold text-[#E5D9C6] tracking-tight">
							{title}
						</h2>
						<div className="luxury-line w-12 mt-1"></div>
					</div>
				</div>
			)}

			<div className="flex items-center justify-between">
				<div>
					{showSearch && (
						<div className="relative w-80">
							<Search className="absolute left-3 top-1/2 -translate-y-1/2 text-[#CBB26A]/50 h-4 w-4" />
							<Input
								placeholder={searchPlaceholder}
								value={searchQuery}
								onChange={handleSearch}
								className="pl-10 bg-[#2A241C] border-[#CBB26A]/20 focus-visible:ring-[#CBB26A]/30 focus-visible:border-[#CBB26A]/40 text-[#E5D9C6] placeholder:text-[#CBB26A]/40 h-9 text-sm"
							/>
						</div>
					)}
				</div>

				<div className="flex items-center gap-2">
					{showColumnSelector && (
						<DropdownMenu>
							<DropdownMenuTrigger asChild>
								<Button
									variant="outline"
									className="gap-2 border-[#CBB26A]/20 bg-[#2A241C] hover:bg-[#CBB26A]/10 hover:border-[#CBB26A]/40 text-[#E5D9C6] h-9"
								>
									<Settings className="h-3.5 w-3.5 text-[#CBB26A]/70" />
									<span className="text-sm">Customize</span>
								</Button>
							</DropdownMenuTrigger>
							<DropdownMenuContent
								align="end"
								className="bg-[#2A241C] border-[#CBB26A]/20"
							>
								{table
									.getAllColumns()
									.filter((column) => column.getCanHide())
									.map((column) => {
										return (
											<DropdownMenuCheckboxItem
												key={column.id}
												className="capitalize text-[#E5D9C6] focus:bg-[#CBB26A]/10 focus:text-[#CBB26A]"
												checked={column.getIsVisible()}
												onCheckedChange={(value) =>
													column.toggleVisibility(!!value)
												}
											>
												{column.id.replace(/_/g, ' ')}
											</DropdownMenuCheckboxItem>
										);
									})}
							</DropdownMenuContent>
						</DropdownMenu>
					)}

					{showFilter && (
						<Button
							variant="outline"
							size="sm"
							className="gap-2 border-[#CBB26A]/20 bg-[#2A241C] hover:bg-[#CBB26A]/10 hover:border-[#CBB26A]/40 text-[#E5D9C6] h-9"
							onClick={onFilterClick}
						>
							<Filter className="h-3.5 w-3.5 text-[#CBB26A]/70" />
							<span className="text-sm">Filter</span>
						</Button>
					)}

					{showItemsPerPage && (
						<DropdownMenu>
							<DropdownMenuTrigger asChild>
								<Button
									variant="outline"
									className="gap-2 border-[#CBB26A]/20 bg-[#2A241C] hover:bg-[#CBB26A]/10 hover:border-[#CBB26A]/40 text-[#E5D9C6] h-9"
								>
									<span className="text-sm">
										{itemsPerPageState} per page
									</span>
								</Button>
							</DropdownMenuTrigger>
							<DropdownMenuContent
								align="end"
								className="bg-[#2A241C] border-[#CBB26A]/20"
							>
								{TableItemPerPageList.map((num) => (
									<DropdownMenuCheckboxItem
										key={num}
										checked={itemsPerPageState === num}
										onCheckedChange={() =>
											handleItemsPerPageChange(num)
										}
										className="text-[#E5D9C6] focus:bg-[#CBB26A]/10 focus:text-[#CBB26A]"
									>
										{num}
									</DropdownMenuCheckboxItem>
								))}
							</DropdownMenuContent>
						</DropdownMenu>
					)}

					{customButtons &&
						customButtons.map((button, index) => (
							<React.Fragment key={index}>{button}</React.Fragment>
						))}

					{showAddButton && (
						<Button
							size="sm"
							className="gap-2 bg-[#CBB26A] hover:bg-[#CBB26A]/90 text-[#1A1510] font-medium h-9 px-4"
							onClick={onAddClick}
						>
							<PlusCircle className="h-3.5 w-3.5" />
							{buttonTitle}
						</Button>
					)}
				</div>
			</div>

			<div className="rounded-lg border border-[#CBB26A]/15 overflow-hidden bg-[#1F1B16] shadow-lg ">
				<Table>
					<TableHeader className="bg-[#2A241C]">
						{table.getHeaderGroups().map((headerGroup) => (
							<TableRow
								key={headerGroup.id}
								className="border-b border-[#CBB26A]/15 hover:bg-transparent"
							>
								{headerGroup.headers.map((header) => (
									<TableHead
										key={header.id}
										className="h-10 py-2 px-4"
									>
										{flexRender(
											header.column.columnDef.header,
											header.getContext()
										)}
									</TableHead>
								))}
							</TableRow>
						))}
					</TableHeader>
					<TableBody>
						{table.getRowModel().rows?.length ? (
							table.getRowModel().rows.map((row, index) => (
								<TableRow
									key={row.id}
									data-state={row.getIsSelected() && 'selected'}
									className={`
										border-b border-[#CBB26A]/10 
										hover:bg-[#CBB26A]/5 
										transition-colors duration-150
										${index % 2 === 0 ? 'bg-transparent' : 'bg-[#CBB26A]/[0.02]'}
									`}
								>
									{row.getVisibleCells().map((cell) => (
										<TableCell key={cell.id} className="py-3 px-4">
											{flexRender(
												cell.column.columnDef.cell,
												cell.getContext()
											)}
										</TableCell>
									))}
								</TableRow>
							))
						) : (
							<TableRow>
								<TableCell
									colSpan={tanstackColumns.length}
									className="text-center h-24 text-[#CBB26A]/50"
								>
									No results found
								</TableCell>
							</TableRow>
						)}
					</TableBody>
				</Table>
			</div>

			{showPagination && (
				<div className="flex items-center justify-end mt-2">
					{renderPageNumbers(currentPage, totalPages, handlePageChange)}
				</div>
			)}
		</div>
	);
}
