import { useMemo, useRef } from 'react';

interface Batch<T> {
    ids: T[];
    resolves: Array<(value: unknown) => void>;
    rejects: Array<(reason?: unknown) => void>;
}

export function useDebounceBatch<T>(
    handler: (items: T[]) => Promise<unknown>,
    delay: number,
) {
    const pendingRef = useRef<Batch<T> | null>(null);
    const timerRef = useRef<number | null>(null);

    return useMemo(() => {
        return (item: T) => {
            return new Promise((resolve, reject) => {
                if (!pendingRef.current) {
                    pendingRef.current = {
                        ids: [],
                        resolves: [],
                        rejects: [],
                    };
                }

                pendingRef.current.ids.push(item);
                pendingRef.current.resolves.push(resolve);
                pendingRef.current.rejects.push(reject);

                if (timerRef.current) {
                    window.clearTimeout(timerRef.current);
                }

                timerRef.current = window.setTimeout(async () => {
                    const batch = pendingRef.current;

                    pendingRef.current = null;
                    timerRef.current = null;

                    if (!batch) return;

                    try {
                        const result = await handler(batch.ids);
                        batch.resolves.forEach(resolveBatch => resolveBatch(result));
                    } catch (error) {
                        batch.rejects.forEach(rejectBatch => rejectBatch(error));
                    }
                }, delay);
            });
        };
    }, [delay, handler]);
}