import { ref, onMounted, onUnmounted } from "vue";
import { router } from "@inertiajs/vue3";

/**
 * Composable for infinite scroll with Inertia v2.
 *
 * @param {Function} getProp - () => the current paginator object from Inertia props
 * @param {string} propName - the prop key name to reload
 * @param {string} pageParam - query string parameter name for page number
 * @param {Function} getRouteUrl - () => current URL to reload
 */
export function useInfiniteList(getProp, propName, pageParam, getRouteUrl) {
    const items = ref([]);
    const currentPage = ref(1);
    const lastPage = ref(1);
    const isLoadingMore = ref(false);
    const sentinelRef = ref(null);
    let observer = null;

    function syncFromProp() {
        const prop = getProp();
        if (!prop) return;
        lastPage.value = prop.last_page ?? 1;
    }

    function appendFromProp() {
        const prop = getProp();
        if (!prop?.data) return;
        // append only new items (avoid duplicates by id)
        const existingIds = new Set(items.value.map((i) => i.id));
        const newItems = prop.data.filter((i) => !existingIds.has(i.id));
        items.value.push(...newItems);
    }

    function reset(initialProp) {
        items.value = initialProp?.data ?? [];
        currentPage.value = initialProp?.current_page ?? 1;
        lastPage.value = initialProp?.last_page ?? 1;
    }

    function loadMore() {
        if (isLoadingMore.value) return;
        if (currentPage.value >= lastPage.value) return;

        const nextPage = currentPage.value + 1;
        isLoadingMore.value = true;

        const params = new URLSearchParams(window.location.search);
        params.set(pageParam, nextPage);

        router.reload({
            url: `${window.location.pathname}?${params.toString()}`,
            only: [propName],
            preserveScroll: true,
            preserveState: true,
            onSuccess: () => {
                appendFromProp();
                currentPage.value = nextPage;
                isLoadingMore.value = false;
            },
            onError: () => {
                isLoadingMore.value = false;
            },
        });
    }

    onMounted(() => {
        observer = new IntersectionObserver(
            (entries) => {
                if (entries[0].isIntersecting) {
                    loadMore();
                }
            },
            { rootMargin: "200px" }
        );

        if (sentinelRef.value) {
            observer.observe(sentinelRef.value);
        }
    });

    onUnmounted(() => {
        observer?.disconnect();
    });

    return {
        items,
        currentPage,
        lastPage,
        isLoadingMore,
        sentinelRef,
        reset,
        syncFromProp,
        appendFromProp,
        loadMore,
    };
}
