import { __decorate, __metadata } from "tslib";
import { Host, h, } from "@stencil/core";
import { BEM } from "../../utils/bem";
import { ListenToBreakpoints, balBreakpoints } from "../../utils/breakpoints";
import { balBrowser } from "../../utils/browser";
import { ListenToConfig, defaultConfig, } from "../../utils/config";
import { stopEventBubbling } from "../../utils/form-input";
import { isDescendant, waitAfterIdleCallback, waitForComponent } from "../../utils/helpers";
import { Logger } from "../../utils/log";
import { ListenToMutation } from "../../utils/mutation";
import { BalScrollHandler } from "../../utils/scroll";
import { sanitizeSvg } from "../../utils/svg";
import { gatherTabInformation, handleFlyoutFocusOut, handleTabKeyDown } from "./bal-nav-focus.util";
import { i18nNavBars } from "./bal-nav.i18n";
import { NavMetaButton } from "./models/bal-nav-meta-button";
import { NavMetaLinkItem } from "./models/bal-nav-meta-link-item";
export class Nav {
    constructor() {
        this.navId = `bal-nav-${NavIds++}`;
        this.bodyScrollHandler = new BalScrollHandler();
        this.isTouch = balBreakpoints.isTouch;
        this.isDesktop = balBreakpoints.isDesktop;
        this.language = defaultConfig.language;
        this.region = defaultConfig.region;
        this.isFlyoutActive = false;
        this.hasRenderedWithFlyoutActive = false;
        /**
         * Link level structure.
         */
        this.options = [];
        this.linkItems = [];
        /**
         * Link level structure.
         */
        this.buttons = [];
        this.metaButtons = [];
        this.mutationObserverActive = true;
        /**
         * EVENT BINDING
         * ------------------------------------------------------
         */
        this.onOptionChange = async () => {
            this.activeMetaLinkValue = undefined;
            this.activeMenuLinkValue = undefined;
            this.linkItems = this.options.map(option => new NavMetaLinkItem(option, this));
        };
        this.onMetaButtonChange = async () => {
            this.metaButtons = this.buttons.map(button => new NavMetaButton(button, this));
        };
        this.onTouchToggleFlyout = (_ev) => {
            this.closeAllPopups();
            this.toggleFlyout();
            if (balBrowser.hasWindow && window.scrollY > 0) {
                window.scrollTo(0, 0);
            }
            if (this.isFlyoutActive) {
                this.bodyScrollHandler.disable();
            }
            else {
                this.bodyScrollHandler.enable();
            }
        };
        this.onPopupOpen = (triggers) => {
            if (this.isTouch) {
                if (balBrowser.hasWindow && window.scrollY > 0) {
                    window.scrollTo(0, 0);
                }
            }
            triggers.forEach(trigger => {
                if (trigger.classList.contains('bal-nav__popup--desktop')) {
                    trigger.inverted = false;
                }
                else if (trigger.classList.contains('bal-nav__popup--touch-bottom')) {
                    trigger.color = 'primary';
                }
                else if (trigger.classList.contains('bal-nav__popup--touch-top')) {
                    trigger.color = 'primary';
                }
            });
            this.bodyScrollHandler.disable();
        };
        this.onPopupClose = (triggers) => {
            if (!this.isFlyoutActive) {
                this.bodyScrollHandler.enable();
            }
            triggers.forEach(trigger => {
                if (trigger.classList.contains('bal-nav__popup--desktop')) {
                    trigger.inverted = true;
                }
                else if (trigger.classList.contains('bal-nav__popup--touch-bottom')) {
                    trigger.color = 'info';
                }
                else if (trigger.classList.contains('bal-nav__popup--touch-top')) {
                    trigger.color = 'light';
                }
            });
        };
        this.onMetaBarTabChange = (ev) => {
            if (ev.detail !== this.activeMetaLinkValue) {
                this.activeMetaLinkValue = ev.detail;
                const activeMetaItem = this.linkItems.find(item => item.value === this.activeMetaLinkValue);
                if (activeMetaItem && activeMetaItem.mainLinkItems.length > 0) {
                    this.activeMenuLinkValue = activeMetaItem.mainLinkItems[0].value;
                }
            }
        };
        this.onMenuBarTabChange = (value) => {
            if (this.activeMenuLinkValue === value) {
                this.toggleFlyout();
            }
            else {
                this.openFlyout();
            }
            this.activeMenuLinkValue = value;
        };
    }
    createLogger(log) {
        this.log = log;
    }
    async optionChanged() {
        this.onOptionChange();
        this.updateTabs();
    }
    async buttonChanged() {
        this.onMetaButtonChange();
    }
    /**
     * LIFECYCLE
     * ------------------------------------------------------
     */
    connectedCallback() {
        this.bodyScrollHandler.connect();
    }
    componentWillLoad() {
        this.onOptionChange();
        this.onMetaButtonChange();
        this.updateTabs();
    }
    disconnectedCallback() {
        this.bodyScrollHandler.disconnect();
    }
    /**
     * LISTENERS
     * ------------------------------------------------------
     */
    listenToPopupChanges(event) {
        const target = event.target;
        if (target && target.nodeName === 'BAL-POPUP') {
            const id = target.id;
            const triggers = Array.from(this.el.querySelectorAll(`[bal-popup="${id}"]`));
            if (event.detail === true) {
                this.onPopupOpen(triggers);
                const isTouchMetaTopButtonClicked = triggers.some(triggerEl => triggerEl.classList.contains('bal-nav__popup--touch-top'));
                if (isTouchMetaTopButtonClicked) {
                    this.closeFlyout();
                }
            }
            else {
                this.onPopupClose(triggers);
            }
        }
    }
    async clickOnOutside(ev) {
        var _a, _b, _c, _d, _e;
        if (this.isDesktop) {
            if (this.hasRenderedWithFlyoutActive) {
                const targetIsInMetaBar = (_b = (_a = this.metaBarEl) === null || _a === void 0 ? void 0 : _a.querySelector('.bal-nav-meta-bar__container')) === null || _b === void 0 ? void 0 : _b.contains(ev.target);
                const targetIsInMenuBar = (_d = (_c = this.menuBarEl) === null || _c === void 0 ? void 0 : _c.querySelector('.bal-nav-menu-bar__container')) === null || _d === void 0 ? void 0 : _d.contains(ev.target);
                if (!targetIsInMetaBar && !targetIsInMenuBar) {
                    this.closeFlyout();
                    const tabs = (_e = this.menuBarEl) === null || _e === void 0 ? void 0 : _e.querySelector('.bal-tabs');
                    tabs.closeAccordion();
                }
            }
        }
    }
    mutationListener() {
        this.onMetaButtonChange();
    }
    breakpointListener(breakpoints) {
        if (this.isTouch !== breakpoints.touch) {
            this.isTouch = breakpoints.touch;
            this.isDesktop = breakpoints.desktop;
            this.closeAllPopups();
            this.closeFlyout();
        }
        if (this.isTouch) {
            this.updateTabs();
        }
    }
    linkItemClickListener(item) {
        if (item && item.toJson) {
            this.balNavItemClick.emit(item.toJson());
        }
    }
    accordionClickListener(item) {
        if (this.isTouch && item) {
            this.updateActiveItem(item);
        }
    }
    /**
     * @internal define config for the component
     */
    async configChanged(state) {
        this.language = state.language;
        this.region = state.region;
    }
    /**
     * GETTERS
     * ------------------------------------------------------
     */
    get activeMenuLinkItems() {
        const foundLinkItem = this.linkItems.find(item => item.value === this.activeMetaLinkValue);
        if (foundLinkItem) {
            return foundLinkItem.mainLinkItems;
        }
        return [];
    }
    get activeMenuLinkItem() {
        const foundLinkItem = this.activeMenuLinkItems.find(item => item.value === this.activeMenuLinkValue);
        return foundLinkItem ? foundLinkItem : undefined;
    }
    /**
     * PRIVATE METHODS
     * ------------------------------------------------------
     */
    toggleFlyout() {
        if (this.isFlyoutActive) {
            this.closeFlyout();
        }
        else {
            this.openFlyout();
        }
    }
    closeFlyout() {
        this.isFlyoutActive = false;
    }
    openFlyout() {
        this.isFlyoutActive = true;
    }
    async updateActiveItem(item) {
        if ('NavMetaLinkItem' === item.type) {
            this.activeMetaLinkValue = this.activeMetaLinkValue === item.value ? undefined : item.value;
            this.activeMenuLinkValue = undefined;
        }
        if ('NavMenuLinkItem' === item.type) {
            this.activeMenuLinkValue = this.activeMenuLinkValue === item.value ? undefined : item.value;
        }
        await waitForComponent(this.el);
        await waitAfterIdleCallback();
        const elementToScroll = this.el.querySelector(`#${item.id}`);
        if (elementToScroll) {
            elementToScroll.scrollIntoView({
                behavior: 'smooth',
            });
            // location.href = '#'
            // location.href = `#${item.id}`
        }
    }
    updateTabs() {
        var _a, _b;
        const previousActiveMetaLinkValue = this.activeMetaLinkValue;
        const newActiveMetaLinkValue = ((_a = this.linkItems.find(item => item.active)) === null || _a === void 0 ? void 0 : _a.value) || previousActiveMetaLinkValue;
        if (previousActiveMetaLinkValue !== newActiveMetaLinkValue) {
            this.activeMetaLinkValue = newActiveMetaLinkValue;
        }
        const previousActiveMenuLinkValue = this.activeMenuLinkValue;
        const newActiveMenuLinkValue = ((_b = this.activeMenuLinkItems.find(item => item.active)) === null || _b === void 0 ? void 0 : _b.value) || previousActiveMenuLinkValue;
        if (previousActiveMenuLinkValue !== newActiveMenuLinkValue) {
            this.activeMenuLinkValue = newActiveMenuLinkValue;
        }
    }
    closeAllPopups() {
        const popups = Array.from(this.el.querySelectorAll('bal-popup'));
        popups.forEach(popup => popup.dismiss());
    }
    /**
     * RENDER
     * ------------------------------------------------------
     */
    render() {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j;
        const block = BEM.block('nav');
        const flyoutBlock = block.element('flyout');
        this.hasRenderedWithFlyoutActive = this.isFlyoutActive;
        return (h(Host, { key: 'dae60e87a7091b449e1f75eab64b12ce35fb05ea', id: this.navId, class: Object.assign({}, block.class()) }, h("div", { key: '649fcb126503a271bc248ee96e68b425a923e5d3', class: {
                'bal-nav-meta-bar-transform': true,
                'bal-nav-meta-bar-transform-touch': this.isTouch,
            } }, this.isDesktop ? (h("bal-nav-meta-bar", { variant: "primary", size: "small", position: "sticky-top", ref: metaBarEl => (this.metaBarEl = metaBarEl) }, h("bal-stack", { space: "auto" }, this.linkItems.length > 1 ? (h("bal-tabs", { inverted: true, context: "meta", value: this.activeMetaLinkValue, "aria-label": i18nNavBars[this.language].mainNavigation, onBalChange: ev => this.onMetaBarTabChange(ev) }, this.linkItems.map(item => item.render({
            flyoutId: `${this.navId}-menu-flyout`,
        })))) : (h("span", null)), h("bal-stack", { id: "bal-nav__meta-buttons", space: "x-small", "fit-content": true }, this.metaButtons.map(button => button.renderAtMetaBar()))))) : (''), this.isDesktop ? (h("bal-nav-menu-bar", { position: "fixed-top", ref: menuBarEl => (this.menuBarEl = menuBarEl) }, h("bal-stack", { space: "auto", "space-row": "none", "use-wrap": true }, this.renderLogo(), h("bal-tabs", { context: "navigation", accordion: true, value: this.activeMenuLinkValue, "aria-label": i18nNavBars[this.language].navigation }, (_a = this.linkItems
            .find(item => item.value === this.activeMetaLinkValue)) === null || _a === void 0 ? void 0 : _a.mainLinkItems.map((item, index) => item.render({
            flyoutId: `${this.navId}-menu-flyout`,
            onClick: () => this.onMenuBarTabChange(item.value),
            onTabPress: (ev) => {
                if (this.isFlyoutActive) {
                    const isBackwards = ev.shiftKey;
                    const info = gatherTabInformation({
                        activeMetaLinkValue: this.activeMetaLinkValue,
                        activeMenuLinkValue: this.activeMenuLinkValue,
                        linkItems: this.linkItems,
                    });
                    handleTabKeyDown(info, {
                        el: this.el,
                        navId: this.navId,
                        isFlyoutActive: this.isFlyoutActive,
                        isBackwards,
                        item,
                        stopEventBubbling: () => stopEventBubbling(ev),
                        closeFlyout: () => this.closeFlyout(),
                    });
                }
            },
        })))), this.isFlyoutActive ? (h("bal-nav-menu-flyout", { navId: this.navId, "aria-label": i18nNavBars[this.language].subNavigation, onBalFocusOut: (ev) => {
                if (this.isFlyoutActive) {
                    stopEventBubbling(ev);
                    const info = gatherTabInformation({
                        activeMetaLinkValue: this.activeMetaLinkValue,
                        activeMenuLinkValue: this.activeMenuLinkValue,
                        linkItems: this.linkItems,
                    });
                    const isBackwards = isDescendant(this.el, ev.detail.relatedTarget);
                    handleFlyoutFocusOut(info, {
                        el: this.el,
                        isBackwards,
                    });
                }
            } }, h("bal-nav-link", { role: "listitem", variant: "overview", href: (_c = (_b = this.activeMenuLinkItem) === null || _b === void 0 ? void 0 : _b.overviewLink) === null || _c === void 0 ? void 0 : _c.href, target: (_e = (_d = this.activeMenuLinkItem) === null || _d === void 0 ? void 0 : _d.overviewLink) === null || _e === void 0 ? void 0 : _e.target, onClick: () => { var _a; return this.linkItemClickListener((_a = this.activeMenuLinkItem) === null || _a === void 0 ? void 0 : _a.overviewLink); } }, (_g = (_f = this.activeMenuLinkItem) === null || _f === void 0 ? void 0 : _f.overviewLink) === null || _g === void 0 ? void 0 :
            _g.label, ' ', ((_j = (_h = this.activeMenuLinkItem) === null || _h === void 0 ? void 0 : _h.overviewLink) === null || _j === void 0 ? void 0 : _j.label) ? '➞' : ''), this.renderGridLinks(this.activeMenuLinkItem))) : (''))) : (''), h("div", { key: '6499f09da6ff07093492b342ee5851600eccd391' }, h("slot", { key: '83f00bc33f0587edf5145def059525712b62637d' }))), this.isTouch ? (h("bal-nav-meta-bar", { variant: "white", size: "normal" }, h("bal-stack", { space: "auto" }, this.renderLogo(), h("bal-stack", { space: "x-small", "fit-content": true }, this.metaButtons.map(button => button.renderAtTouchTopMetaBar()), h("bal-button", { square: true, color: this.isFlyoutActive ? 'primary' : 'light', icon: this.isFlyoutActive ? 'close' : 'menu-bars', "aria-label": this.isFlyoutActive ? i18nNavBars[this.language].close : i18nNavBars[this.language].open, onClick: ev => this.onTouchToggleFlyout(ev) }))))) : (''), this.isTouch ? (h("div", { class: Object.assign(Object.assign({}, flyoutBlock.class()), flyoutBlock.modifier('visible').class(this.isFlyoutActive)) }, h("nav", { class: Object.assign({}, flyoutBlock.element('container').class()) }, h("ul", { class: Object.assign({}, block.element('mobile-meta-list').class()) }, this.linkItems.map(item => item.renderTouch({
            activeMetaLinkValue: this.activeMetaLinkValue,
            activeMenuLinkValue: this.activeMenuLinkValue,
        })))))) : (''), this.isTouch && this.isFlyoutActive ? (h("bal-nav-meta-bar", { stayOnTopOfBackdrop: true, variant: "grey", size: "normal" }, h("bal-stack", { space: "x-small", align: "center" }, this.metaButtons.map(button => button.renderAtTouchBottomMetaBar())))) : ('')));
    }
    renderGridLinks(linkItem) {
        var _a, _b;
        if (!linkItem) {
            return '';
        }
        return (h("bal-nav-link-grid", null, h("bal-nav-link-grid-col", null, (_a = linkItem.sectionLinkItems) === null || _a === void 0 ? void 0 : _a.map(itemGroup => itemGroup.render())), h("bal-nav-link-grid-col", { "static-col": true }, (_b = linkItem.serviceLinkItems) === null || _b === void 0 ? void 0 : _b.map(itemGroup => itemGroup.render()))));
    }
    renderTouchMenuAccordions(metaItem) {
        return (h("bal-list", { "accordion-one-level": true, class: "pt-xxx-small pb-normal" }, metaItem.mainLinkItems.map(menuItem => {
            var _a, _b, _c;
            return menuItem.isLink ? (h("bal-list-item", { key: menuItem.label, "sub-accordion-item": true, href: menuItem.href, target: menuItem.target }, h("bal-list-item-content", null, h("bal-list-item-title", { "visual-level": "medium", level: "span" }, menuItem.label)))) : (h("bal-list-item", { key: menuItem.label, accordion: true, "sub-accordion-item": true }, h("bal-list-item-accordion-head", { icon: "nav-go-down", "accordion-open": menuItem.active }, h("bal-list-item-content", null, h("bal-list-item-title", { "visual-level": "medium", level: "span" }, menuItem.label))), h("bal-list-item-accordion-body", null, h("div", { style: { width: '100%' } }, h("bal-nav-link", { role: "listitem", variant: "overview", href: (_a = menuItem.overviewLink) === null || _a === void 0 ? void 0 : _a.href, target: (_b = menuItem.overviewLink) === null || _b === void 0 ? void 0 : _b.target, onClick: () => this.linkItemClickListener(menuItem.overviewLink) }, (_c = menuItem.overviewLink) === null || _c === void 0 ? void 0 : _c.label), h("div", { class: "pt-normal" }, this.renderGridLinks(menuItem))))));
        })));
    }
    renderLogo() {
        var _a, _b, _c, _d, _e, _f, _g, _h;
        const Link = ((_a = this.logo) === null || _a === void 0 ? void 0 : _a.href) ? 'a' : ((_b = this.logo) === null || _b === void 0 ? void 0 : _b.clickable) ? 'button' : 'div';
        let Logo = h("bal-logo", { animated: true });
        const logoImageUrl = (_c = this.logo) === null || _c === void 0 ? void 0 : _c.url;
        const logoSvg = sanitizeSvg((_d = this.logo) === null || _d === void 0 ? void 0 : _d.svg);
        if (logoImageUrl) {
            Logo = h("img", { height: 32, style: { maxHeight: '32px' }, src: logoImageUrl, alt: "Logo" });
        }
        if (logoSvg) {
            Logo = (h("div", { innerHTML: logoSvg, role: "img", "aria-label": "Logo", style: { display: 'flex', height: '32px', maxHeight: '32px', minWidth: '32px' } }));
        }
        return (h(Link, { class: "bal-nav__logo", "aria-label": (_e = this.logo) === null || _e === void 0 ? void 0 : _e.ariaLabel, title: (_f = this.logo) === null || _f === void 0 ? void 0 : _f.htmlTitle, href: (_g = this.logo) === null || _g === void 0 ? void 0 : _g.href, target: (_h = this.logo) === null || _h === void 0 ? void 0 : _h.target, onClick: () => {
                var _a, _b;
                return this.balNavItemClick.emit({
                    value: 'logo',
                    label: 'Logo',
                    href: (_a = this.logo) === null || _a === void 0 ? void 0 : _a.href,
                    target: (_b = this.logo) === null || _b === void 0 ? void 0 : _b.target,
                });
            } }, Logo));
    }
    static get is() { return "bal-nav"; }
    static get originalStyleUrls() {
        return {
            "$": ["bal-nav.sass"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["bal-nav.css"]
        };
    }
    static get properties() {
        return {
            "logo": {
                "type": "unknown",
                "attribute": "logo",
                "mutable": false,
                "complexType": {
                    "original": "BalProps.BalNavLogoLink",
                    "resolved": "BalNavLogoLink",
                    "references": {
                        "BalProps": {
                            "location": "global",
                            "id": "global::BalProps"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Link level structure."
                },
                "getter": false,
                "setter": false
            },
            "options": {
                "type": "unknown",
                "attribute": "options",
                "mutable": false,
                "complexType": {
                    "original": "BalProps.BalNavOptions",
                    "resolved": "BalNavMetaLinkItem[]",
                    "references": {
                        "BalProps": {
                            "location": "global",
                            "id": "global::BalProps"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Link level structure."
                },
                "getter": false,
                "setter": false,
                "defaultValue": "[]"
            },
            "buttons": {
                "type": "unknown",
                "attribute": "buttons",
                "mutable": false,
                "complexType": {
                    "original": "BalProps.BalNavMetaButtons",
                    "resolved": "BalNavMetaButton[]",
                    "references": {
                        "BalProps": {
                            "location": "global",
                            "id": "global::BalProps"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Link level structure."
                },
                "getter": false,
                "setter": false,
                "defaultValue": "[]"
            }
        };
    }
    static get states() {
        return {
            "isTouch": {},
            "isDesktop": {},
            "language": {},
            "region": {},
            "isFlyoutActive": {},
            "activeMetaLinkValue": {},
            "activeMenuLinkValue": {},
            "linkItems": {},
            "metaButtons": {}
        };
    }
    static get events() {
        return [{
                "method": "balNavItemClick",
                "name": "balNavItemClick",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when a nav link item is clicked. This event can be used to\nadd data tracking"
                },
                "complexType": {
                    "original": "BalEvents.BalNavItemClickDetail",
                    "resolved": "BalNavClickedItem",
                    "references": {
                        "BalEvents": {
                            "location": "global",
                            "id": "global::BalEvents"
                        }
                    }
                }
            }];
    }
    static get methods() {
        return {
            "configChanged": {
                "complexType": {
                    "signature": "(state: BalConfigState) => Promise<void>",
                    "parameters": [{
                            "name": "state",
                            "type": "BalConfigState",
                            "docs": ""
                        }],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        },
                        "BalConfigState": {
                            "location": "import",
                            "path": "../../utils/config",
                            "id": "src/utils/config/index.ts::BalConfigState"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "",
                    "tags": [{
                            "name": "internal",
                            "text": "define config for the component"
                        }]
                }
            }
        };
    }
    static get elementRef() { return "el"; }
    static get watchers() {
        return [{
                "propName": "options",
                "methodName": "optionChanged"
            }, {
                "propName": "buttons",
                "methodName": "buttonChanged"
            }];
    }
    static get listeners() {
        return [{
                "name": "balChange",
                "method": "listenToPopupChanges",
                "target": undefined,
                "capture": false,
                "passive": false
            }, {
                "name": "click",
                "method": "clickOnOutside",
                "target": "document",
                "capture": false,
                "passive": true
            }];
    }
}
__decorate([
    Logger('bal-nav'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Function]),
    __metadata("design:returntype", void 0)
], Nav.prototype, "createLogger", null);
__decorate([
    ListenToMutation({ tags: ['bal-popup'], waitAfterFramePrint: true }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", void 0)
], Nav.prototype, "mutationListener", null);
__decorate([
    ListenToBreakpoints(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", void 0)
], Nav.prototype, "breakpointListener", null);
__decorate([
    ListenToConfig(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], Nav.prototype, "configChanged", null);
let NavIds = 0;
