import React, { useRef } from "react";

type Param = {
    elementRef?: React.RefObject<Element | undefined>;
    className?: string;
    elId?: string;
    options?: IntersectionObserverInit;
    removeIntersected?: boolean;
    delay?: number;
};

export default function useIntersectionObserver({
    elementRef,
    className,
    options,
    removeIntersected,
    delay,
    elId,
}: Param) {
    let timeoutRef = useRef<any>(null);

    const [isIntersecting, setIsIntersecting] = React.useState(false);
    const [refresh, setRefresh] = React.useState(0);

    const observerTriggerDelay = delay || 200;

    const observerCallback: IntersectionObserverCallback = React.useCallback(
        (entries, observer) => {
            const entry = entries[0];
            window.clearTimeout(timeoutRef.current);

            if (entry.isIntersecting) {
                timeoutRef.current = setTimeout(() => {
                    setIsIntersecting(true);

                    if (removeIntersected) {
                        observer.unobserve(entry.target);
                    }
                }, observerTriggerDelay);
            } else {
                setIsIntersecting(false);
            }
        },
        [],
    );

    React.useEffect(() => {
        const element = elId
            ? document.getElementById(elId)
            : elementRef?.current;
        const elements = className
            ? document.querySelectorAll(`.${className}`)
            : null;

        if (!element && !className && refresh < 5) {
            requestAnimationFrame(() => {
                setTimeout(() => {
                    setRefresh(refresh + 1);
                }, 2000);
            });
            return;
        }

        const observer = new IntersectionObserver(observerCallback, {
            rootMargin: "0px 0px 0px 0px",
            ...options,
        });

        if (elements) {
            elements.forEach((el) => {
                observer.observe(el);
            });
        } else if (element) {
            observer.observe(element);
        }
    }, [refresh]);

    return { isIntersecting };
}
