import { useCallback, useRef } from 'react';
class SectionSelector {
    scrollTop = 0;
    node;
    boxHeight;
    childrenHeights = [];
    maxScrollTop;
    constructor(node) {
        this.node = node;
        this.refreshFromDOM();
    }
    refreshFromDOM() {
        this.boxHeight = this.node.scrollHeight;
        this.childrenHeights = Array.prototype.map.call(this.node.children, (child) => child.offsetHeight);
        this.maxScrollTop = this.boxHeight - this.node.offsetHeight;
    }
    getVisibleRange(scrollTop = this.scrollTop) {
        const top = scrollTop;
        const height = this.node.offsetHeight;
        const bottom = scrollTop + this.node.offsetHeight;
        return {
            top,
            bottom,
            height,
        };
    }
    select = (scrollTop) => {
        this.refreshFromDOM();
        const relativeCurrentHeight = (scrollTop * this.boxHeight) / this.maxScrollTop;
        let heightSum = 0;
        for (let i = 0, len = this.childrenHeights.length; i < len; i++) {
            heightSum += this.childrenHeights[i];
            if (heightSum > relativeCurrentHeight) {
                return i;
            }
        }
        return this.childrenHeights.length - 1;
    };
}
export const useContainerScrollObserver = (callback) => {
    const containerNodeRef = useRef(null);
    const sectionSelectorRef = useRef(null);
    const update = useCallback((scrollTop) => {
        callback(sectionSelectorRef.current.select(scrollTop));
    }, []);
    const scrollRafRef = useRef(null);
    const onScroll = useCallback(() => {
        if (scrollRafRef.current) {
            cancelAnimationFrame(scrollRafRef.current);
            scrollRafRef.current = null;
        }
        requestAnimationFrame(() => {
            scrollRafRef.current = null;
            update(containerNodeRef.current.scrollTop);
        });
    }, []);
    const setupScroll = useCallback((node) => {
        if (node) {
            containerNodeRef.current = node;
            node.addEventListener('scroll', onScroll, { passive: true });
            sectionSelectorRef.current = new SectionSelector(node);
        }
        else {
            containerNodeRef.current?.removeEventListener('scroll', onScroll);
            sectionSelectorRef.current = null;
        }
    }, []);
    const ref = setupScroll;
    return {
        ref,
        scrollToIndex: useCallback((index) => {
            const container = containerNodeRef.current;
            const node = container.childNodes[index];
            node.scrollIntoView({
                behavior: 'smooth',
            });
        }, []),
    };
};
