import GNS from "../GNS.js";
import AriaButton from "./AriaButton.js";
const NAME = "MainNav";
const NS = `${GNS}.${NAME}`;
const $ = GNS.jQuery;
$.easing[NS] = x => 1 - Math.pow(1 - x, 3.5);
const SUPPORT = {
    HISTORY: window.history && history.replaceState,
    PASSIVE_EVENT: ((support = false) => {
        try { addEventListener("x", null, { get passive() { support = true; } }); } catch (e) {}
        return support;
    })()
};
const CLASS = {
    activeLink: "main-nav__link--active",
    fixableFixed: "page-header__top--fixed"
};
const DATA = {
    focus: "main-nav-focus",
    active: "main-nav-active",
    scrollTo: "main-nav-scroll-to",
    ignore: "main-nav-ignore",
    call: "main-nav-call"
};
const SELECTOR = {
    self: ".main-nav",
    itemsWrapper: ".main-nav__items",
    item: ".main-nav__item",
    link: ".main-nav__link",
    activeLink: "." + CLASS.activeLink,
    mobileOpener: ".main-nav__opener.js-aria-button",
    fixable: ".page-header__top",
    scrollTarget: "[data-main-nav-target='true']",
    linkWithHash: "a[href*='#']:not([href='#']):not([data-" + DATA.ignore + "='true'])"
};
const EVENT = {
    change: NS + ".change"
};
const ELEMENT = {
    $self: null,
    $itemsWrapper: null,
    $acitveLink: null,
    $mobileOpener: null,
    $fixable: null,
    $scrollTargets: null,
    currentScrollTarget: null,
    $scrollingElement: null
};
const OPTION = {
    SCROLL_DURATION_BASE: 400,
    TARGET_IN_VIEW_DIV: 4
};
const SCROLL_OFFSET = {
    "(max-height: 29.9375em)": 0,
    "(min-height: 30em) and (max-width: 47.9375em)": 60,
    "(min-height: 30em) and (max-width: 63.9375em)": 66,
    "(min-height: 40em) and (max-width: 78.6875em)": 77,
    "(min-height: 40em)": 84
};
let isFixed = false;
let skipFindLinkToActivateOnScroll;
let skipFindLinkToActivateOnScrollTimeout;
let scrollThrottle;
function getFixPosition() {
    return window.matchMedia(Object.keys(SCROLL_OFFSET)[0]).matches ? Infinity: 0;
}
function getScrollOffset() {
    let offset = 0;
    Object.keys(SCROLL_OFFSET).some(mq => {
        if (window.matchMedia(mq).matches) {
            offset = SCROLL_OFFSET[mq];
            return true;
        }
    });
    return offset;
}
function getDataOption(option, ...$elements) {
    let elements = $elements.filter($el => typeof $el.attr("data-" + option) !== "undefined");
    return elements.length ? elements[0].attr("data-" + option): undefined;
}
function toggleFixed(state) {
    isFixed = state;
    ELEMENT.$fixable[state ? "addClass" : "removeClass"](CLASS.fixableFixed);
}
function toggleMobileOpener(state) {
    if (ELEMENT.$mobileOpener[0]) {
        AriaButton.setState(ELEMENT.$mobileOpener[0], state);
    }
}
function getScrollableHeight() {
    return document.documentElement.scrollHeight - window.innerHeight;
}
function deactivateActiveLink() {
    ELEMENT.$self
        .find(SELECTOR.activeLink)
        .removeClass(CLASS.activeLink);
    ELEMENT.$acitveLink = null;
}
function activateLink($link) {
    if (!$link || (ELEMENT.$acitveLink && ELEMENT.$acitveLink[0] === $link[0])) {
        return;
    }
    deactivateActiveLink();
    if ($link.length && $link.closest(SELECTOR.self).length) {
        $link.addClass(CLASS.activeLink);
        ELEMENT.$acitveLink = $link;
        updateHistory($link);
    }
}
function updateHistory($link = null) {
    if ($link === null && SUPPORT.HISTORY) {
        history.replaceState(null, null, "#");
        GNS.$win.trigger(EVENT.change, [null]);
    }
    if ($link && $link[0]) {
        let linkHash = $link[0].hash;
        if (SUPPORT.HISTORY && history.state !== linkHash) {
            history.replaceState(linkHash, null, linkHash);
            GNS.$win.trigger(EVENT.change, [linkHash.replace("#", "")]);
        }
    }
}
function make$ElementFocusableAndFocus($element) {
    if (typeof $element.attr("tabindex") === "undefined") {
        $element
            .attr("tabindex", -1)
            .off("blur." + NS + " focusout." + NS)
            .one("blur." + NS + " focusout." + NS, () => {
                $element
                    .removeAttr("tabindex")
                    .off("blur." + NS + " focusout." + NS);
            });
    }
    let currentScrollTop = GNS.$win.scrollTop();
    $element[0].focus({
        preventScroll: true
    });
    GNS.$win.scrollTop(currentScrollTop);
}
function moveFocus($link, $focusTarget) {
    let focusSelector = getDataOption(DATA.focus, $link, $focusTarget);
    if (focusSelector) {
        $focusTarget = $focusTarget.find(focusSelector);
    }
    if ($focusTarget.length) {
        make$ElementFocusableAndFocus($focusTarget);
    }
}
function isTargetInView(rect) {
    return rect.top <= window.innerHeight / OPTION.TARGET_IN_VIEW_DIV &&
        rect.bottom > window.innerHeight / OPTION.TARGET_IN_VIEW_DIV;
}
function isLocalLink(linkEl) {
    return linkEl &&
        location.hostname === linkEl.hostname &&
        location.pathname.replace(/^\//, "") === linkEl.pathname.replace(/^\//, "");
}
function findMainNav$LinkByTargetId(idOrHash) {
    let id = idOrHash.replace("#", "");
    let $link = ELEMENT.$itemsWrapper.find(`[href*="#${id}"]`);
    return $link.filter((i, el) => el.hash === ("#" + id));
}
function getScrollTargetTop($link, $target) {
    let scrollTo = parseFloat(getDataOption(DATA.scrollTo, $link, $target));
    return Math.min(
        Math.max(
            !isNaN(scrollTo) && isFinite(scrollTo) ?
                $target.offset().top - (window.innerHeight * (scrollTo / 100)):
                $target.offset().top - getScrollOffset(),
            0
        ),
        getScrollableHeight()
    );
}
function onScrollAnimationBreakByUser(event) {
    if (event.type === "touchstart" && !GNS.$t(event.target).closest(SELECTOR.link).length) {
        event.preventDefault();
    }
    ELEMENT.$scrollingElement.stop();
    clearTimeout(skipFindLinkToActivateOnScrollTimeout);
    skipFindLinkToActivateOnScroll = false;
    activateByScroll(true);
}
function onScrollAnimationStop() {
    GNS.$t(document.body).removeAttr("aria-busy");
    destroyScrollAnimationBreakByUser();
    clearTimeout(scrollThrottle);
    scrollThrottle = null;
    handleFixableEl();
}
function initScrollAnimationBreakByUser() {
    destroyScrollAnimationBreakByUser();
    window.addEventListener("mousewheel", onScrollAnimationBreakByUser);
    window.addEventListener("DOMMouseScroll", onScrollAnimationBreakByUser);
    window.addEventListener("keydown", onScrollAnimationBreakByUser);
    window.addEventListener("touchstart", onScrollAnimationBreakByUser, SUPPORT.PASSIVE_EVENT ? { passive: false }: false);
}
function destroyScrollAnimationBreakByUser() {
    window.removeEventListener("mousewheel", onScrollAnimationBreakByUser);
    window.removeEventListener("DOMMouseScroll", onScrollAnimationBreakByUser);
    window.removeEventListener("keydown", onScrollAnimationBreakByUser);
    window.removeEventListener("touchstart", onScrollAnimationBreakByUser);
}
function animateScrollTop(scrollTop, scrollDuration, onComplete) {
    GNS.$t(document.body).attr("aria-busy", "true");
    skipFindLinkToActivateOnScroll = true;
    debounceSkipFindLinkToActivateOnScroll();
    initScrollAnimationBreakByUser();
    ELEMENT.$scrollingElement
        .stop()
        .animate(
            { scrollTop: scrollTop },
            {
                duration: scrollDuration,
                easing: NS,
                always: onScrollAnimationStop,
                complete: () => {
                    if (onComplete && !onComplete.run) {
                        onComplete();
                        onComplete.run = true;
                    }
                }
            }
        );
}
function getScrollDuration(targetScrollTop) {
    let scrollAmount = Math.abs(GNS.$win.scrollTop() - targetScrollTop);
    return OPTION.SCROLL_DURATION_BASE + (OPTION.SCROLL_DURATION_BASE * scrollAmount / getScrollableHeight());
}
function callOnScrollAnimCompleteCallFn($link, $scrollTarget) {
    let call = getDataOption(DATA.call, $link, $scrollTarget);
    if (call && typeof GNS[call] === "function") {
        GNS[call]();
    } else if (call && typeof window[call] === "function") {
        window[call]();
    }
}
function get$LinkToActivate($link, $scrollTarget) {
    let activateLinkSelector = getDataOption(DATA.active, $link, $scrollTarget);
    if (activateLinkSelector) {
        return $(activateLinkSelector);
    }
    let linkIsInsideMainNav = $link.closest(SELECTOR.self).length;
    return linkIsInsideMainNav ? $link: findMainNav$LinkByTargetId($link[0].hash);
}
function get$LinkToActivateFromTargetEl(scrollTargetEl) {
    let activateLinkSelector = scrollTargetEl.getAttribute("data-" + DATA.active);
    return activateLinkSelector ? $(activateLinkSelector): findMainNav$LinkByTargetId(scrollTargetEl.id);
}
function scrollToTargetByLink(linkElOr$link) {
    if (!linkElOr$link || (linkElOr$link.jquery && !linkElOr$link.length)) {
        return false;
    }
    let $link = linkElOr$link.jquery ? linkElOr$link: $(linkElOr$link);
    let targetId = $link[0].hash.replace("#", "");
    let $scrollTarget = ELEMENT.$scrollTargets.filter("#" + targetId);
    if ($scrollTarget.length) {
        $scrollTarget.attr("id", "");
        $link.blur();
        ELEMENT.currentScrollTarget = $scrollTarget[0];
        let scrollTargetTop = getScrollTargetTop($link, $scrollTarget);
        animateScrollTop(
            scrollTargetTop,
            getScrollDuration(scrollTargetTop),
            () => {
                moveFocus($link, $scrollTarget);
                callOnScrollAnimCompleteCallFn($link, $scrollTarget);
            }
        );
        activateLink(get$LinkToActivate($link, $scrollTarget));
        toggleMobileOpener(false);
        $scrollTarget.attr("id", targetId);
        return true;
    }
    return false;
}
function findCurrentScrollTargetEl() {
    let currentScrollTargetEl = null;
    let currentScrollTargetTop = null;
    ELEMENT.$scrollTargets.each((i, targetEl) => {
        let rect = targetEl.getBoundingClientRect();
        if (isTargetInView(rect) && (rect.top > currentScrollTargetTop || currentScrollTargetTop === null)) {
            currentScrollTargetEl = targetEl;
            currentScrollTargetTop = rect.top;
        }
    });
    return currentScrollTargetEl;
}
function debounceSkipFindLinkToActivateOnScroll() {
    clearTimeout(skipFindLinkToActivateOnScrollTimeout);
    skipFindLinkToActivateOnScrollTimeout = setTimeout(() => {
        skipFindLinkToActivateOnScroll = false;
    }, 150);
}
function activateByScroll(forceActivation) {
    if (!forceActivation && skipFindLinkToActivateOnScroll) {
        return debounceSkipFindLinkToActivateOnScroll();
    }
    let currentScrollTargetEl = findCurrentScrollTargetEl();
    if (forceActivation || ELEMENT.currentScrollTarget !== currentScrollTargetEl) {
        ELEMENT.currentScrollTarget = currentScrollTargetEl;
        if (!currentScrollTargetEl) {
            deactivateActiveLink();
            updateHistory(null);
            return;
        }
        let $link = get$LinkToActivateFromTargetEl(currentScrollTargetEl);
        activateLink($link);
        updateHistory($link);
    }
}
function onMobileOpenerPressed() {
    make$ElementFocusableAndFocus(ELEMENT.$itemsWrapper);
}
function scrollTo(targetOrLinkEl) {
    if (typeof targetOrLinkEl !== "string") {
        if (GNS.$t(targetOrLinkEl).is(SELECTOR.link)) {
            return scrollToTargetByLink(targetOrLinkEl);
        }
        return scrollToTargetByLink(
            findMainNav$LinkByTargetId(
                targetOrLinkEl.jquery ? targetOrLinkEl[0].id: targetOrLinkEl.id
            )
        );
    }
    return scrollToTargetByLink(
        findMainNav$LinkByTargetId(targetOrLinkEl)
    );
}
function handleFixableEl() {
    let scrollTop = GNS.$win.scrollTop();
    if (scrollTop > getFixPosition()) {
        if (!isFixed) {
            toggleFixed(true);
        }
    } else if (isFixed) {
        toggleFixed(false);
    }
}
function handleLinkWithHashClick(event) {
    if (isLocalLink(event.currentTarget) && scrollToTargetByLink(event.currentTarget)) {
        event.preventDefault();
    }
}
function handleScrollAndResize() {
    if (!scrollThrottle) {
        if (!isFixed) {
            handleFixableEl();
        }
        scrollThrottle = setTimeout(() => {
            activateByScroll();
            handleFixableEl();
            scrollThrottle = null;
        }, 66.666);
    }
}
function initEvents() {
    GNS.$win.on("scroll." + NS + " resize." + NS, handleScrollAndResize);
    GNS.$doc.on("click." + NS, SELECTOR.linkWithHash, handleLinkWithHashClick);
    GNS.$win.trigger("scroll." + NS);
    window.addEventListener("ariabutton__change", event => {
        if (event.target === ELEMENT.$mobileOpener[0] && event.detail.state) {
            onMobileOpenerPressed();
        }
    });
}
function initElements() {
    ELEMENT.$self = $(SELECTOR.self);
    ELEMENT.$itemsWrapper = ELEMENT.$self.find(SELECTOR.itemsWrapper);
    ELEMENT.$mobileOpener = ELEMENT.$self.find(SELECTOR.mobileOpener);
    ELEMENT.$fixable = $(SELECTOR.fixable);
    ELEMENT.$scrollTargets = $(SELECTOR.scrollTarget);
    ELEMENT.$scrollingElement = $(document.scrollingElement || "html, body");
}
function init() {
    if (!init.initialized) {
        initElements();
        initEvents();
        init.initialized = true;
    }
}
export default { init, scrollTo };