"use client";
import { useEffect, useState, useCallback, Ref, useImperativeHandle } from "react";
import SortableTable, { Pagination, SortableTableProps } from "./Table";
import { PrismaClient } from "@repo/db";
import { getData } from "./pagiantedTableActions";

export interface PaginatedTableRef {
	refresh: () => void;
}

interface PaginatedTableProps<TData> extends Omit<SortableTableProps<TData>, "data"> {
	prismaModel: keyof PrismaClient;
	filter?: Record<string, any>;
	rowsPerPage?: number;
	showEditButton?: boolean;
	searchFields?: string[];
	include?: Record<string, boolean>;
	strictQuery?: boolean;
	leftOfSearch?: React.ReactNode;
	rightOfSearch?: React.ReactNode;
	leftOfPagination?: React.ReactNode;
	hide?: boolean;
	ref?: Ref<PaginatedTableRef>;
}

export function PaginatedTable<TData>({
	prismaModel,
	rowsPerPage = 10,
	showEditButton = false,
	searchFields = [],
	filter,
	include,
	ref,
	strictQuery = false,
	leftOfSearch,
	rightOfSearch,
	leftOfPagination,
	hide,
	...restProps
}: PaginatedTableProps<TData>) {
	const [data, setData] = useState<TData[]>([]);
	const [page, setPage] = useState(0);
	const [total, setTotal] = useState(0);
	const [searchTerm, setSearchTerm] = useState("");
	const [debouncedSearchTerm, setDebouncedSearchTerm] = useState(searchTerm);
	const [orderBy, setOrderBy] = useState<Record<string, "asc" | "desc">>(
		restProps.initialOrderBy
			? restProps.initialOrderBy.reduce(
					(acc, sort) => {
						acc[sort.id] = sort.desc ? "desc" : "asc";
						return acc;
					},
					{} as Record<string, "asc" | "desc">,
				)
			: {},
	);

	const RefreshTableData = async () => {
		getData(
			prismaModel,
			rowsPerPage,
			page * rowsPerPage,
			debouncedSearchTerm,
			searchFields,
			filter,
			include,
			orderBy,
			strictQuery
				? restProps.columns
						.filter((col: any) => "accessorKey" in col)
						.map((col: any) => col.accessorKey)
						.reduce((acc: Record<string, any>, key: string) => {
							acc[key] = true;
							return acc;
						}, {})
				: undefined,
		).then((result) => {
			if (result) {
				setData(result.data);
				setTotal(result.total);
			}
		});
	};

	useEffect(() => {
		RefreshTableData();
	}, [filter, orderBy]);

	useImperativeHandle(ref, () => ({
		refresh: () => {
			RefreshTableData();
		},
	}));

	const debounce = (func: Function, delay: number) => {
		let timer: NodeJS.Timeout;
		return (...args: any[]) => {
			clearTimeout(timer);
			timer = setTimeout(() => func(...args), delay);
		};
	};

	const handleSearchChange = useCallback(
		debounce((value: string) => {
			setDebouncedSearchTerm(value);
		}, 500),
		[],
	);

	useEffect(() => {
		RefreshTableData();
	}, [page, debouncedSearchTerm]);

	return (
		<div className="space-y-4 m-4">
			<div className="flex items-center  gap-2">
				<div className="flex-1">{leftOfSearch}</div>
				{searchFields.length > 0 && (
					<input
						type="text"
						placeholder="Suchen..."
						value={searchTerm}
						onChange={(e) => {
							setSearchTerm(e.target.value);
							handleSearchChange(e.target.value);
							setPage(0); // Reset to first page on search
						}}
						className="input input-bordered w-full max-w-xs justify-end"
					/>
				)}
				<div className="flex justify-center">{rightOfSearch}</div>
			</div>
			{!hide && (
				<SortableTable
					data={data}
					prismaModel={prismaModel}
					showEditButton={showEditButton}
					setOrderBy={setOrderBy}
					{...restProps}
				/>
			)}
			<div className="flex items-between">
				{leftOfPagination}
				{!hide && (
					<Pagination totalPages={Math.ceil(total / rowsPerPage)} page={page} setPage={setPage} />
				)}
			</div>
		</div>
	);
}
