import { router } from '@inertiajs/react';
import { useEffect, useRef } from 'react';
import type { DraftStore, DraftType } from '@/lib/draft-store';

type UseDraftSaveOptions<D> = {
    type: DraftType;
    data: D;
    userId?: number;
    extraId?: number;
    delay?: number;
    store: Pick<DraftStore<D>, 'save' | 'clear'>;
};

export function useDraftSave<D>({
    type,
    data,
    userId,
    extraId,
    delay = 500,
    store,
}: UseDraftSaveOptions<D>) {
    const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
    const dataRef = useRef(data);
    dataRef.current = data;
    const submittedRef = useRef(false);

    useEffect(() => {
        const offBefore = router.on('before', (event) => {
            if (event.detail.visit.method !== 'get') {
                submittedRef.current = true;
            }
        });
        const offError = router.on('error', () => {
            submittedRef.current = false;
        });

        return () => {
            offBefore();
            offError();
        };
    }, []);

    useEffect(() => {
        if (timeoutRef.current) {
            clearTimeout(timeoutRef.current);
        }

        timeoutRef.current = setTimeout(() => {
            if (!submittedRef.current) {
                store.save(type, dataRef.current, userId, extraId);
            }

            timeoutRef.current = null;
        }, delay);

        return () => {
            if (timeoutRef.current) {
                clearTimeout(timeoutRef.current);
            }
        };
    }, [data, type, userId, extraId, delay, store]);

    useEffect(() => {
        return () => {
            if (timeoutRef.current) {
                clearTimeout(timeoutRef.current);
            }

            if (submittedRef.current) {
                store.clear(type, userId, extraId);
            } else {
                store.save(type, dataRef.current, userId, extraId);
            }
        };
    }, [type, userId, extraId, store]);
}

export function createDraftHook<D>(
    store: Pick<DraftStore<D>, 'save' | 'load' | 'clear'>,
) {
    return function useDraft(
        type: DraftType,
        data: D,
        userId?: number,
        extraId?: number,
        delay = 500,
    ) {
        return useDraftSave({
            type,
            data,
            userId,
            extraId,
            delay,
            store,
        });
    };
}
