import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, } from "react";
const MAX_BALLS = 7;
const eachBallWidthEm = 1.2;
const CENTER_GUIDE_BALL = 1;
export var PaginationIndicatorMode;
(function (PaginationIndicatorMode) {
    /** This will make the guide ball be kept on center  */
    PaginationIndicatorMode[PaginationIndicatorMode["CENTERED"] = 0] = "CENTERED";
    /** This will make the guide ball move, while the indicator balls keep in place */
    PaginationIndicatorMode[PaginationIndicatorMode["START"] = 1] = "START";
})(PaginationIndicatorMode || (PaginationIndicatorMode = {}));
export function PaginationIndicatorView({ size, page: currentPage, pages: decimalPages, className, onClickPage, mode = PaginationIndicatorMode.CENTERED, infinite, }) {
    const maxBalls = useMemo(() => (infinite ? 5 : MAX_BALLS), [infinite]);
    const page = useMemo(() => {
        const floor = Math.floor(decimalPages);
        const modulus = decimalPages % floor;
        if (currentPage > floor) {
            const currentFloorModulus = currentPage % floor;
            const equivalent = (currentFloorModulus * 100) / modulus;
            return floor + equivalent / 100;
        }
        else {
            return currentPage;
        }
    }, [currentPage, decimalPages]);
    const rand = useMemo(() => Math.random().toString(), []);
    const pageIndex = page - 1;
    const pages = useMemo(() => Math.ceil(decimalPages), [decimalPages]);
    const numBalls = useMemo(() => {
        const numBalls = pages >= maxBalls ? maxBalls : Math.ceil(pages);
        return numBalls;
    }, [pages]);
    const indexForTheBallsCenter = useMemo(() => (infinite ? numBalls - 5 : numBalls - 1) / 2, [numBalls, infinite]);
    const balls = useMemo(() => {
        const indexForLastPages = pages + 1 - indexForTheBallsCenter;
        /**
         * Is the page index (position of the center)
         * after the first pages and
         * before the last pages */
        const isCenterPage = numBalls >= maxBalls &&
            pageIndex > indexForTheBallsCenter &&
            pageIndex < indexForLastPages - 1;
        let modulus = pageIndex %
            (1 + (indexForTheBallsCenter - Math.floor(indexForTheBallsCenter)));
        const resetPageIndex = isCenterPage
            ? indexForTheBallsCenter + modulus
            : pages < maxBalls
                ? pageIndex
                : pageIndex >= indexForLastPages - 1
                    ? numBalls - (pages - pageIndex)
                    : pageIndex;
        const left = eachBallWidthEm * resetPageIndex;
        const { pushBallsToRightBy, pushBallsToLeftBy, pushGuideToRightBy } = mode === PaginationIndicatorMode.CENTERED
            ? {
                pushBallsToRightBy: Math.min(pages, maxBalls) * eachBallWidthEm,
                pushBallsToLeftBy: left,
                pushGuideToRightBy: 0,
            }
            : {
                pushBallsToRightBy: (eachBallWidthEm - 0.5) / 2,
                pushBallsToLeftBy: 0,
                pushGuideToRightBy: left,
            };
        let pushToLeft = 0;
        return new Array(CENTER_GUIDE_BALL + numBalls)
            .fill(undefined)
            .map((_, i) => {
            const isLastBall = i === numBalls - 1;
            const isFirstBall = i === 0;
            if (i === numBalls) {
                const diameter = 0.45 * 2;
                const padding = (eachBallWidthEm - diameter) / 2;
                return (_jsx("rect", { fill: "#fff", width: `${diameter}em`, height: `${diameter}em`, x: `${pushBallsToRightBy - padding + pushGuideToRightBy - pushToLeft}em`, y: `${padding}em`, rx: `${diameter / 2}em` }));
            }
            const ballSize = numBalls < maxBalls
                ? 0.5
                : page <= indexForTheBallsCenter + 1 && isLastBall
                    ? 0
                    : pageIndex >= indexForLastPages - 1 && isFirstBall
                        ? 0
                        : isCenterPage
                            ? isFirstBall
                                ? 0.5 - modulus * 0.5
                                : isLastBall
                                    ? modulus * 0.5
                                    : 0.5
                            : 0.5;
            if (i === 0 && mode === PaginationIndicatorMode.START)
                pushToLeft = (0.5 - ballSize) * 2.4;
            return (_jsx("rect", { width: `${ballSize * 1.2}em`, height: `${ballSize * 1.2}em`, x: `${pushBallsToRightBy +
                    i * eachBallWidthEm -
                    pushBallsToLeftBy -
                    pushToLeft}em`, y: `${(eachBallWidthEm - ballSize * 1.2) / 2}em`, rx: `${(ballSize * 1.2) / 2}em`, onClick: () => {
                    if (onClickPage) {
                        const pageClicked = (!isCenterPage
                            ? pageIndex >= indexForLastPages - 1
                                ? Math.floor(page) - resetPageIndex - 1
                                : 0
                            : Math.floor(page) - (indexForTheBallsCenter + 1)) +
                            1 +
                            i;
                        onClickPage(Math.round(pageClicked));
                    }
                } }, `guide-${i}`));
        });
    }, [indexForTheBallsCenter, pageIndex, pages]);
    const [guideBall, ...pageBalls] = balls.reverse();
    let width = eachBallWidthEm * Math.min(pages, maxBalls) * 2;
    if (mode === PaginationIndicatorMode.START)
        width /= 2;
    return (_jsxs("svg", { version: "1.1", xmlns: "http://www.w3.org/2000/svg", className: className, style: {
            width: `${width}em`,
            minWidth: `${width}em`,
            height: "1.2em",
            fontSize: `${size}px`,
        }, children: [_jsxs("filter", { id: `goo-${rand}`, children: [_jsx("feGaussianBlur", { in: "SourceGraphic", result: "blur", stdDeviation: "5" }), _jsx("feColorMatrix", { in: "blur", mode: "matrix", values: "1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 18 -7", result: "goo" }), _jsx("feBlend", { in2: "goo", in: "SourceGraphic", result: "mix" })] }), _jsx("mask", { id: `mask-${rand}`, children: _jsxs("g", { filter: `url(#${`goo-${rand}`})`, fill: "#fff", children: [[pageBalls], guideBall] }) }), _jsx("rect", { x: "0", y: "0", mask: `url(#${`mask-${rand}`})`, width: "100%", height: "100%", style: { fill: "var(--digital-blue)" } }), onClickPage && (_jsx("g", { opacity: 0, style: { cursor: "pointer" }, children: pageBalls }))] }));
}
export function AnimatedPaginationIndicator(props) {
    const prevPage = useRef(props.page);
    const [pageProgress, setPageProgress] = useState(props.page);
    useEffect(() => {
        const diff = props.page - prevPage.current;
        const diffPerStep = diff / 60;
        const interval = setInterval(() => {
            setPageProgress((prev) => {
                const next = prev + diffPerStep;
                if (diff < 0) {
                    if (next <= props.page) {
                        clearInterval(interval);
                        return props.page;
                    }
                }
                else {
                    if (next >= props.page) {
                        clearInterval(interval);
                        return props.page;
                    }
                }
                return Number(next.toFixed(2));
            });
        }, props.duration / 60);
        return () => {
            prevPage.current = props.page;
            clearInterval(interval);
        };
    }, [props.page]);
    return _jsx(PaginationIndicatorView, { ...props, page: pageProgress });
}
function _PaginationIndicator({ scrollableRef, estimatedWidth, size, className = "", onClickPage, mode, infinite, }, ref) {
    const [currentPage, setCurrentPage] = useState(1);
    const [defs, setDefs] = useState();
    const refreshPages = useCallback(() => {
        if (!scrollableRef.current)
            return;
        const maxWidth = estimatedWidth === undefined
            ? scrollableRef.current.scrollWidth
            : estimatedWidth;
        const pages = maxWidth / scrollableRef.current.clientWidth;
        if (pages > 1)
            setDefs({
                pages: infinite ? pages + 2 : pages,
            });
    }, [estimatedWidth, infinite]);
    useEffect(() => refreshPages(), [refreshPages]);
    const updatePageIndicators = useCallback((target, pages) => {
        if (!scrollableRef.current)
            return;
        const eachPageWidth = scrollableRef.current.clientWidth;
        const page = 1 + target.scrollLeft / eachPageWidth;
        const lastPageProgress = Math.floor(pages) + 1;
        const maximumProgress = pages + 1;
        const diffToMax = maximumProgress - lastPageProgress;
        const currentProgressOnDiff = page - lastPageProgress;
        if (page > lastPageProgress) {
            const p = lastPageProgress + currentProgressOnDiff / diffToMax;
            setCurrentPage(p);
        }
        else
            setCurrentPage(page);
    }, []);
    useImperativeHandle(ref, () => ({
        refreshPages,
    }), []);
    useEffect(() => {
        if (!defs)
            return;
        const el = scrollableRef.current;
        const onScroll = (e) => updatePageIndicators(e.currentTarget, defs.pages);
        updatePageIndicators(el, defs.pages);
        el.addEventListener("scroll", onScroll, {
            passive: true,
        });
        return () => {
            el.removeEventListener("scroll", onScroll);
        };
    }, [defs]);
    const pages = useMemo(() => (defs ? defs.pages : undefined), [defs]);
    return !pages ? null : (_jsx(PaginationIndicatorView, { pages: pages, page: currentPage, size: size, className: className, onClickPage: onClickPage, mode: mode, infinite: infinite }));
}
/**
 * A cool component to indicate how many pages are
 **/
/**
 * A pagination indicator component that displays the current page
 * and total number of pages using animated circular indicators.
 * It updates visually when scrolling through pages.
 */
const PaginationIndicator = forwardRef(_PaginationIndicator);
export default PaginationIndicator;
//# sourceMappingURL=PaginationIndicator.js.map