import { __assign } from "tslib";
import { jsx as _jsx } from "react/jsx-runtime";
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import isNil from '../utils/isNil';
import { smoothScroll } from '../utils/scroll';
import { ElevatorContext } from './context';
import { ElevatorAnchor } from './ElevatorAnchor';
import { ElevatorLinks } from './ElevatorLinks';
var SCROLL_DURATION = 200;
var getDefaultContainer = function () { return window; };
export var Elevator = function (_a) {
    var children = _a.children, onChange = _a.onChange, targetOffset = _a.targetOffset, getContainer = _a.getContainer, defaultActiveLink = _a.defaultActiveLink, propOffsetTop = _a.offsetTop, propActiveLink = _a.activeLink;
    var getContainerResult = getContainer === null || getContainer === void 0 ? void 0 : getContainer();
    var _b = useState(new Map()), anchorElementsMap = _b[0], setAnchorElementsMap = _b[1];
    var _c = useState(''), internalActiveLink = _c[0], setInternalActiveLink = _c[1];
    var activeLink = useMemo(function () { return (!isNil(propActiveLink) ? propActiveLink : internalActiveLink); }, [propActiveLink, internalActiveLink]);
    var isScrolling = useRef(false);
    var handleAnchorEnter = function (link) {
        setInternalActiveLink(link);
        if (isScrolling.current || link === activeLink)
            return;
        onChange === null || onChange === void 0 ? void 0 : onChange(link, activeLink);
    };
    var offsetTop = useMemo(function () {
        var containerHeight = getDefaultContainer().innerHeight;
        if (getContainerResult) {
            containerHeight = getContainerResult.getBoundingClientRect().height;
        }
        var defaultOffsetTop = containerHeight / 2;
        return !isNil(propOffsetTop)
            ? containerHeight - (propOffsetTop || 1)
            : defaultOffsetTop;
    }, [propOffsetTop, getContainerResult]);
    var handleRegisterAnchor = useCallback(function (link, el) {
        setAnchorElementsMap(function (prev) {
            var map = new Map(prev);
            map.set(link, el);
            return map;
        });
    }, []);
    var handleUnRegister = useCallback(function (link) {
        setAnchorElementsMap(function (prev) {
            var map = new Map(prev);
            map.delete(link);
            return map;
        });
    }, []);
    var handleScrollToLink = function (link, controlled) {
        if (controlled === void 0) { controlled = false; }
        var el = anchorElementsMap.get(link);
        if (!el)
            return;
        var bounds = el.getBoundingClientRect();
        var container = getDefaultContainer();
        var containerTop = 0;
        var scrollTop = container.scrollY;
        var scrollLeft = container.scrollX;
        if (getContainerResult) {
            container = getContainerResult;
            var containerBounds = container.getBoundingClientRect();
            containerTop = containerBounds.top;
            scrollTop = container.scrollTop;
            scrollLeft = container.scrollLeft;
        }
        var scrollTopTarget = bounds.top - containerTop + scrollTop - (targetOffset || 0);
        isScrolling.current = true;
        smoothScroll(container, scrollLeft, scrollTopTarget, SCROLL_DURATION).then(function () {
            isScrolling.current = false;
            !controlled && (onChange === null || onChange === void 0 ? void 0 : onChange(link, activeLink));
        });
    };
    var handleLinkClick = function (link) {
        if (isNil(propActiveLink)) {
            handleScrollToLink(link);
        }
        else if (link !== activeLink) {
            onChange === null || onChange === void 0 ? void 0 : onChange(link, activeLink);
        }
    };
    useEffect(function () {
        if (!isNil(propActiveLink) && propActiveLink !== internalActiveLink) {
            handleScrollToLink(propActiveLink, true);
        }
        if (isNil(propActiveLink) && defaultActiveLink) {
            handleScrollToLink(defaultActiveLink);
        }
    }, [propActiveLink, anchorElementsMap, defaultActiveLink]);
    return (_jsx(ElevatorContext.Provider, __assign({ value: {
            activeLink: activeLink,
            offsetTop: offsetTop,
            getContainer: getContainer,
            onLinkClick: handleLinkClick,
            onAnchorEnter: handleAnchorEnter,
            registerAnchor: handleRegisterAnchor,
            unRegisterAnchor: handleUnRegister,
        } }, { children: children }), void 0));
};
Elevator.Links = ElevatorLinks;
Elevator.Anchor = ElevatorAnchor;
export default Elevator;
