import * as React from 'react';
import { useRef, useState } from 'react';
import { Flex } from 'rebass';
import { useLatest } from '../utils/useLatest';
import usePrevious from '../utils/usePrevious';
const Container = ({ children, index, hidden, observerRef, }) => {
    const [mounted, setMounted] = useState(false);
    React.useEffect(() => {
        const timeoutId = setTimeout(() => {
            // we wait for a bit, so intersection observer
            // has time to kick in before we trigger a rerender
            // to make the element visible if needed
            setMounted(true);
        }, 50);
        return () => clearTimeout(timeoutId);
    }, []);
    const domRef = useRef(null);
    const onMount = (node) => {
        if (node) {
            if (!node.getAttribute('data-index')) {
                throw 'The element you render from "renderItem" should accept a "data-index" prop.';
            }
            observerRef.current?.observe(node);
        }
        else {
            observerRef.current?.unobserve(domRef.current);
        }
        domRef.current = node;
    };
    let child = React.Children.toArray(children)[0];
    const cloneProps = {
        ref: onMount,
        'data-index': index,
    };
    if (hidden || !mounted) {
        cloneProps.style = { ...child.props?.style, visibility: 'hidden' };
    }
    child = React.cloneElement(child, cloneProps);
    return React.createElement(React.Fragment, null, child);
};
export const EllipsisContainer = (props) => {
    const { allowWrap, count, direction, renderItem, renderEllipsis, ...boxProps } = props;
    const domRef = useRef(null);
    const observerRef = useRef(null);
    const [minNotVisibleIndex, setMinNotVisibleIndex] = React.useState(props.count);
    const [visibleSet] = useState(() => new Set());
    const [invisibleSet] = useState(() => new Set());
    const getCount = useLatest(props.count);
    React.useEffect(() => {
        const callback = (entries) => {
            const count = getCount();
            const isVisible = (entry) => entry.intersectionRatio === 1;
            entries.forEach((entry) => {
                const { target } = entry;
                const index = Number(target.getAttribute('data-index'));
                const visible = isVisible(entry);
                if (visible) {
                    visibleSet.add(index);
                    invisibleSet.delete(index);
                }
                else {
                    visibleSet.delete(index);
                    invisibleSet.add(index);
                }
            });
            const minNotVisibleIndex = Math.min(count, ...invisibleSet.values());
            setMinNotVisibleIndex(minNotVisibleIndex);
        };
        if (allowWrap) {
            return;
        }
        const observer = new IntersectionObserver(callback, {
            root: domRef.current,
            threshold: 0.01,
        });
        observerRef.current = observer;
        return () => {
            observer.disconnect();
        };
    }, []);
    const prevCount = usePrevious(count, count);
    React.useLayoutEffect(() => {
        if (allowWrap) {
            return;
        }
        if (minNotVisibleIndex === prevCount) {
            setMinNotVisibleIndex(count);
        }
    }, [count, minNotVisibleIndex, allowWrap]);
    const children = [...new Array(count)].map((_, index) => {
        const remaining = count - 1 - index;
        const hidden = allowWrap ? false : index >= minNotVisibleIndex;
        return (React.createElement(React.Fragment, { key: index },
            React.createElement(Container, { hidden: hidden, index: index, observerRef: observerRef }, renderItem(index, count)),
            !allowWrap && index === minNotVisibleIndex - 1 && remaining
                ? renderEllipsis?.({ remaining }) ?? '...'
                : null));
    });
    return (React.createElement(Flex, { ref: domRef, flexWrap: allowWrap ? 'wrap' : 'nowrap', alignItems: "center", "data-name": "options-container", ...boxProps, flexDirection: direction === 'horizontal' ? 'row' : 'column' }, children));
};
