import { h, } from "@stencil/core";
import { isNestedInIfxComponent } from "../..//shared/utils/dom-utils";
import { detectFramework } from "../..//shared/utils/framework-detection";
import { trackComponent } from "../../shared/utils/tracking";
export class IfxTabs {
    el;
    /** Orientation of tab list, either horizontal or vertical. */
    orientation = "horizontal";
    /** Index of the currently active tab. */
    activeTabIndex = 0;
    /** Stretches tabs to evenly fill the available horizontal space. */
    fullWidth = false;
    /** Text of the Advanced-Tab-Label */
    label;
    /** Number of the Advanced-Tab-Number */
    number = 0;
    /** Subline under the header, only for advanced variant. */
    subline;
    /** Makes the tab header stick to the top of its scrolling oontainer */
    positionSticky = false;
    internalOrientation;
    internalActiveTabIndex = 0;
    tabObjects = [];
    canScrollLeft = false;
    canScrollRight = false;
    atTop = false;
    internalFocusedTabIndex = 0;
    tabRefs = [];
    tabHeaderRefs = [];
    tabsListElement;
    tabFocusHandlers = new Map();
    /** Emitted when the active tab changes (e.g., user selects a different tab). */
    ifxChange;
    updateBorderOnWindowResize() {
        this.updateBorderAndFocus();
        this.updateScrollButtons();
    }
    setActiveAndFocusedTab(index) {
        if (index >= this.tabObjects.length) {
            index = this.tabObjects.length - 1;
        }
        if (index < 0) {
            index = 0;
        }
        if (!this.tabObjects[index]?.disabled) {
            this.internalActiveTabIndex = index;
            this.internalFocusedTabIndex = index;
            // Scroll the active tab into view
            setTimeout(() => this.scrollTabIntoView(index), 0);
        }
    }
    handleTabHeaderChange(e) {
        const tabIndex = e.target.getAttribute("slot").replace("tab-", "");
        this.tabObjects[tabIndex].header = e.detail;
        this.tabObjects = [...this.tabObjects];
    }
    handleScroll() {
        const container = this.el.shadowRoot.querySelector('.tabs-container') || this.el.shadowRoot.querySelector('.tabs-list');
        if (container) {
            const removeSubline = container.getBoundingClientRect().top;
            this.atTop = removeSubline <= 0;
        }
    }
    activeTabIndexChanged(newValue, oldValue) {
        if (newValue !== oldValue) {
            this.setActiveAndFocusedTab(newValue);
        }
    }
    componentWillLoad() {
        this.internalOrientation =
            this.orientation.toLowerCase() === "vertical" ? "vertical" : "horizontal";
        this.onSlotChange();
        this.setActiveAndFocusedTab(this.activeTabIndex);
        this.updateTabStyles();
        this.handleScroll();
    }
    updateTabStyles() {
        this.tabHeaderRefs.forEach((tab, index) => {
            tab.classList.toggle("active", index === this.internalActiveTabIndex);
            tab.setAttribute("aria-selected", index === this.internalActiveTabIndex ? "true" : "false");
        });
    }
    // needed for smooth border transition
    reRenderBorder() {
        const borderElement = this.el.shadowRoot.querySelector(".active-border");
        if (borderElement && this.tabHeaderRefs[this.internalActiveTabIndex]) {
            if (this.orientation === "horizontal") {
                borderElement.style.left = `${this.tabHeaderRefs[this.internalActiveTabIndex].offsetLeft}px`;
                borderElement.style.width = `${this.tabHeaderRefs[this.internalActiveTabIndex].offsetWidth}px`;
                borderElement.style.top = "";
                borderElement.style.height = "";
            }
            else {
                borderElement.style.top = `${this.tabHeaderRefs[this.internalActiveTabIndex].offsetTop}px`;
                borderElement.style.height = `${this.tabHeaderRefs[this.internalActiveTabIndex].offsetHeight}px`;
                borderElement.style.left = "";
                borderElement.style.width = "";
            }
        }
    }
    // when a slot is removed / added
    onSlotChange() {
        const tabs = this.el.querySelectorAll('ifx-tab');
        this.tabObjects = Array.from(tabs).map((tab) => {
            return {
                header: tab?.header,
                disabled: tab?.disabled === true,
                icon: tab?.icon,
                iconPosition: tab?.iconPosition,
                subline: tab?.subline,
                label: tab?.label,
                number: tab?.number,
            };
        });
        this.tabRefs = Array.from(tabs);
        this.tabRefs.forEach((tab, index) => {
            tab.setAttribute("slot", `tab-${index}`);
        });
    }
    async componentDidLoad() {
        if (!isNestedInIfxComponent(this.el)) {
            const framework = detectFramework();
            trackComponent("ifx-tabs", await framework);
        }
        this.updateBorderAndFocus();
        this.updateScrollButtons();
        // Add keyboard event listeners for each tab header
        this.setupTabFocusListeners();
        this.handleScroll();
    }
    setupTabFocusListeners() {
        // Clear any existing handlers
        this.tabFocusHandlers.clear();
        this.tabHeaderRefs.forEach((tab, index) => {
            const handler = () => {
                this.internalFocusedTabIndex = index;
            };
            // Store the handler so we can remove it later
            this.tabFocusHandlers.set(tab, handler);
            tab.addEventListener("focus", handler);
        });
    }
    disconnectedCallback() {
        // Remove keyboard event listeners when component is unmounted
        this.tabFocusHandlers.forEach((handler, tab) => {
            tab.removeEventListener("focus", handler);
        });
        this.tabFocusHandlers.clear();
    }
    componentDidUpdate() {
        this.updateBorderAndFocus();
        requestAnimationFrame(() => {
            this.updateScrollButtons();
        });
    }
    updateBorderAndFocus() {
        this.reRenderBorder();
        this.updateTabFocusability();
    }
    updateTabFocusability() {
        this.tabHeaderRefs.forEach((tab, index) => {
            tab.tabIndex = index === this.internalActiveTabIndex ? 0 : -1;
        });
    }
    focusNextTab() {
        let nextIndex = this.internalFocusedTabIndex + 1;
        while (nextIndex < this.tabHeaderRefs.length &&
            this.tabObjects[nextIndex].disabled) {
            nextIndex++;
        }
        if (nextIndex >= 0 && nextIndex < this.tabHeaderRefs.length) {
            this.internalFocusedTabIndex = nextIndex;
            this.tabHeaderRefs[nextIndex].focus();
        }
    }
    focusPreviousTab() {
        let prevIndex = this.internalFocusedTabIndex - 1;
        while (prevIndex >= 0 && this.tabObjects[prevIndex].disabled) {
            prevIndex--;
        }
        if (prevIndex >= 0 && prevIndex < this.tabHeaderRefs.length) {
            this.internalFocusedTabIndex = prevIndex;
            this.tabHeaderRefs[prevIndex].focus();
        }
    }
    getTabItemClass(index) {
        const isActive = index === this.internalActiveTabIndex && !this.tabObjects[index].disabled;
        const isDisabled = this.tabObjects[index].disabled;
        const iconPosition = this.tabObjects[index].iconPosition;
        const subline = this.tabObjects[index].subline;
        const label = this.tabObjects[index].label;
        const number = this.tabObjects[index].number;
        return `tab-item ${this.fullWidth ? 'full-width' : ""} ${isActive ? 'active' : ''} ${isDisabled ? 'disabled' : ''} ${'icon__' + iconPosition} ${subline ? 'subline' : ''} ${label ? 'label' : ''} ${number ? 'number' : ''}`;
    }
    handleClick(tab, index) {
        if (!tab.disabled) {
            const previousTabIndex = this.internalActiveTabIndex;
            this.internalActiveTabIndex = index;
            this.ifxChange.emit({ previousTab: previousTabIndex, currentTab: index });
            // Center the clicked tab
            setTimeout(() => this.scrollTabIntoView(index), 0);
        }
    }
    handleKeyDown(ev) {
        if (ev.key === "Tab") {
            if (ev.shiftKey) {
                // Shift + Tab
                if (this.internalFocusedTabIndex === 0) {
                    // Allow default behavior to move focus out of component
                    return;
                }
                else {
                    ev.preventDefault();
                    this.focusPreviousTab();
                }
            }
            else {
                // Tab
                if (this.internalFocusedTabIndex === this.tabHeaderRefs.length - 1) {
                    // Allow default behavior to move focus out of component
                    return;
                }
                else {
                    ev.preventDefault();
                    this.focusNextTab();
                }
            }
        }
        else if (ev.key === "Enter") {
            const path = ev.composedPath();
            const isTabHeader = path.some((el) => this.tabHeaderRefs.includes(el));
            if (!isTabHeader) {
                return;
            }
            if (this.internalFocusedTabIndex !== -1 &&
                !this.tabObjects[this.internalFocusedTabIndex].disabled) {
                const previousTabIndex = this.internalActiveTabIndex;
                this.internalActiveTabIndex = this.internalFocusedTabIndex;
                this.ifxChange.emit({
                    previousTab: previousTabIndex,
                    currentTab: this.internalFocusedTabIndex,
                });
                // Center the activated tab
                setTimeout(() => this.scrollTabIntoView(this.internalFocusedTabIndex), 0);
            }
        }
    }
    updateScrollButtons() {
        if (this.shouldDisableScrolling()) {
            this.canScrollLeft = false;
            this.canScrollRight = false;
            return;
        }
        const container = this.tabsListElement;
        if (!container) {
            this.canScrollLeft = false;
            this.canScrollRight = false;
            return;
        }
        const maxScroll = container.scrollWidth - container.clientWidth;
        // No real overflow
        if (maxScroll <= 1) {
            this.canScrollLeft = false;
            this.canScrollRight = false;
            return;
        }
        const currentScroll = container.scrollLeft;
        this.canScrollLeft = currentScroll > 1;
        this.canScrollRight = currentScroll < maxScroll - 1;
    }
    shouldDisableScrolling() {
        return (!this.tabsListElement ||
            this.internalOrientation === "vertical" ||
            this.fullWidth);
    }
    scrollLeft() {
        if (!this.canScrollLeft || !this.tabsListElement)
            return;
        const scrollAmount = Math.min(200, this.tabsListElement.scrollLeft);
        this.tabsListElement.scrollBy({ left: -scrollAmount, behavior: "smooth" });
    }
    scrollRight() {
        if (!this.canScrollRight || !this.tabsListElement)
            return;
        const maxScroll = this.tabsListElement.scrollWidth - this.tabsListElement.clientWidth;
        const currentScroll = this.tabsListElement.scrollLeft;
        const scrollAmount = Math.min(200, maxScroll - currentScroll);
        this.tabsListElement.scrollBy({ left: scrollAmount, behavior: "smooth" });
    }
    onTabsListScroll() {
        this.updateScrollButtons();
    }
    scrollTabIntoView(index) {
        if (this.shouldDisableScrolling() || !this.tabHeaderRefs[index]) {
            return;
        }
        const tabElement = this.tabHeaderRefs[index];
        const container = this.tabsListElement;
        const tabRect = this.getTabCenterInfo(tabElement);
        const containerRect = this.getContainerCenterInfo(container);
        if (Math.abs(tabRect.center - containerRect.center) > 50) {
            let desiredScrollLeft = this.calculateCenteredScrollPosition(tabRect, containerRect);
            // 🔥 clamp tiny values
            if (desiredScrollLeft < 1) {
                desiredScrollLeft = 0;
            }
            const maxScroll = container.scrollWidth - container.clientWidth;
            if (maxScroll - desiredScrollLeft < 1) {
                desiredScrollLeft = maxScroll;
            }
            container.scrollTo({ left: desiredScrollLeft });
        }
    }
    getTabCenterInfo(tabElement) {
        const left = tabElement.offsetLeft;
        const width = tabElement.offsetWidth;
        return {
            left,
            width,
            center: left + width / 2,
        };
    }
    getContainerCenterInfo(container) {
        const scrollLeft = container.scrollLeft;
        const width = container.clientWidth;
        return {
            scrollLeft,
            width,
            center: scrollLeft + width / 2,
        };
    }
    calculateCenteredScrollPosition(tabRect, containerRect) {
        const desiredScrollLeft = tabRect.center - containerRect.width / 2;
        const maxScrollLeft = this.tabsListElement.scrollWidth - containerRect.width;
        return Math.max(0, Math.min(desiredScrollLeft, maxScrollLeft));
    }
    render() {
        return (h("div", { key: '6d50fd3cf2975542fcb0264148857d624b49593e', "aria-label": "navigation tabs", class: `tabs ${this.internalOrientation} ${this.fullWidth ? 'full-width-enabled' : ''}` }, this.internalOrientation === 'horizontal' ? (h("div", { class: `tabs-container ${this.positionSticky ? 'position-sticky' : ''} ${this.atTop ? 'at-top' : ''}` }, h("ifx-icon-button", { shape: "round", variant: "tertiary", icon: "chevronLeft16", size: "s", disabled: false, "aria-label": "Scroll tabs left", onClick: () => this.scrollLeft(), class: `scroll-button scroll-left ${!this.canScrollLeft ? 'hidden' : ""}` }), h("ul", { role: "tablist", class: "tabs-list scrollable", ref: (el) => (this.tabsListElement = el), onScroll: () => this.onTabsListScroll() }, this.tabObjects?.map((tab, index) => (h("li", { class: this.getTabItemClass(index), ref: (el) => (this.tabHeaderRefs[index] = el), onMouseDown: (event) => event.preventDefault(), onClick: () => this.handleClick(tab, index), "aria-selected": index === this.internalActiveTabIndex ? 'true' : 'false', "aria-disabled": tab.disabled ? 'true' : 'false', role: "tab" }, h("div", { class: "top" }, tab?.icon ? h("ifx-icon", { icon: tab.icon }) : "", tab?.header ?
            h("div", { class: "header-wrapper" }, h("p", { class: "header" }, tab.header)) : "", tab?.number ?
            h("div", { class: "number-wrapper" }, h("ifx-indicator", { class: "number", variant: "number", number: tab.number, inverted: false })) : '', tab?.label ?
            h("div", { class: "chip" }, h("span", { class: "label-wrapper" }, h("ifx-chip", { class: "label", placeholder: tab.label, size: "small", variant: "single", theme: "outlined", icon: "", "read-only": "true", "aria-label": "Chip", disabled: tab.disabled, tabindex: "-1" }))) : ''), (tab?.subline || this.subline) && (h("span", { class: "subline-wrapper" }, h("p", { class: "subline" }, tab?.subline ?? this.subline)))))), h("div", { class: "active-border" })), h("ifx-icon-button", { shape: "round", variant: "tertiary", icon: "chevronRight16", size: "s", disabled: false, "aria-label": "Scroll tabs right", onClick: () => this.scrollRight(), class: `scroll-button scroll-right ${!this.canScrollRight ? 'hidden' : ""}` }))) : (h("ul", { role: "tablist", class: `tabs-list ${this.positionSticky ? 'position-sticky' : ''} ${this.atTop ? 'at-top' : ''}` }, this.tabObjects?.map((tab, index) => (h("li", { class: this.getTabItemClass(index), ref: (el) => (this.tabHeaderRefs[index] = el), onMouseDown: (event) => event.preventDefault(), onClick: () => this.handleClick(tab, index), "aria-selected": index === this.internalActiveTabIndex ? 'true' : 'false', "aria-disabled": tab.disabled ? 'true' : 'false', role: "tab" }, h("div", { class: "top" }, tab?.icon ? h("ifx-icon", { icon: tab.icon }) : "", tab?.header ?
            h("div", { class: "header-wrapper" }, h("p", { class: "header" }, tab.header)) : "", tab?.number ?
            h("div", { class: "number-wrapper" }, h("ifx-indicator", { class: "number", variant: "number", number: tab.number, inverted: false })) : '', tab?.label ?
            h("div", { class: "chip" }, h("span", { class: "label-wrapper" }, h("ifx-chip", { class: "label", placeholder: tab.label, size: "small", variant: "single", theme: "outlined", icon: "", "read-only": "true", "aria-label": "Chip", disabled: tab.disabled, tabindex: "-1" }))) : ''), (tab?.subline || this.subline) && (h("span", { class: "subline-wrapper" }, h("p", { class: "subline" }, tab?.subline ?? this.subline)))))), h("div", { class: "active-border" }))), h("div", { key: '7643bca22b4abce96a827037b646987bd24f79d7', class: "tab-content" }, Array.from(this.tabObjects).map((_, index) => (h("div", { style: { display: index === this.internalActiveTabIndex ? 'block' : 'none' } }, h("slot", { name: `tab-${index}` })))))));
    }
    static get is() { return "ifx-tabs"; }
    static get encapsulation() { return "shadow"; }
    static get originalStyleUrls() {
        return {
            "$": ["tabs.scss"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["tabs.css"]
        };
    }
    static get properties() {
        return {
            "orientation": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Orientation of tab list, either horizontal or vertical."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "orientation",
                "defaultValue": "\"horizontal\""
            },
            "activeTabIndex": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Index of the currently active tab."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "active-tab-index",
                "defaultValue": "0"
            },
            "fullWidth": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Stretches tabs to evenly fill the available horizontal space."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "full-width",
                "defaultValue": "false"
            },
            "label": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Text of the Advanced-Tab-Label"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "label"
            },
            "number": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Number of the Advanced-Tab-Number"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "number",
                "defaultValue": "0"
            },
            "subline": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Subline under the header, only for advanced variant."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "subline"
            },
            "positionSticky": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Makes the tab header stick to the top of its scrolling oontainer"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "position-sticky",
                "defaultValue": "false"
            }
        };
    }
    static get states() {
        return {
            "internalOrientation": {},
            "internalActiveTabIndex": {},
            "tabObjects": {},
            "canScrollLeft": {},
            "canScrollRight": {},
            "atTop": {}
        };
    }
    static get events() {
        return [{
                "method": "ifxChange",
                "name": "ifxChange",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when the active tab changes (e.g., user selects a different tab)."
                },
                "complexType": {
                    "original": "any",
                    "resolved": "any",
                    "references": {}
                }
            }];
    }
    static get elementRef() { return "el"; }
    static get watchers() {
        return [{
                "propName": "activeTabIndex",
                "methodName": "activeTabIndexChanged"
            }];
    }
    static get listeners() {
        return [{
                "name": "resize",
                "method": "updateBorderOnWindowResize",
                "target": "window",
                "capture": false,
                "passive": true
            }, {
                "name": "tabHeaderChange",
                "method": "handleTabHeaderChange",
                "target": undefined,
                "capture": false,
                "passive": false
            }, {
                "name": "scroll",
                "method": "handleScroll",
                "target": "window",
                "capture": false,
                "passive": true
            }, {
                "name": "slotchange",
                "method": "onSlotChange",
                "target": undefined,
                "capture": false,
                "passive": false
            }, {
                "name": "keydown",
                "method": "handleKeyDown",
                "target": undefined,
                "capture": false,
                "passive": false
            }];
    }
}
