/**
 * Copyright Aquera Inc 2023
 *
 * This source code is licensed under the BSD-3-Clause license found in the
 * LICENSE file in the root directory of this source tree.
 */
import { __decorate } from "tslib";
import { html } from 'lit';
import { customElement, property, query } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { styles } from './nile-side-bar-action.css';
import NileElement from '../internal/nile-element';
import { animateTo, stopAnimations } from '../internal/animate';
import { getAnimation, setDefaultAnimation } from '../utilities/animation-registry';
import { getTabbableBoundary } from '../internal/tabbable';
import { waitForEvent } from '../internal/event';
import { watch } from '../internal/watch';
import '../nile-popup';
import { DropdownPortalManager } from './portal-manager';
/**
 * Nile side-bar-action component.
 *
 * @tag nile-side-bar-action
 *
 * @slot trigger - The clickable trigger (icon/button).
 * @slot - The dropdown panel content (menu, custom content).
 *
 * @event nile-show - Fired when dropdown opens.
 * @event nile-after-show - Fired after dropdown + animations.
 * @event nile-hide - Fired when dropdown closes.
 * @event nile-after-hide - Fired after dropdown closes + animations.
 */
let NileSideBarAction = class NileSideBarAction extends NileElement {
    constructor() {
        super(...arguments);
        /** Whether the dropdown is open */
        this.open = false;
        /** Preferred placement relative to trigger */
        this.placement = 'bottom-start';
        /** Disable interaction */
        this.disabled = false;
        /** Keep open on select */
        this.stayOpenOnSelect = false;
        /** Offsets */
        this.distance = 0;
        this.skidding = 0;
        /** Hoist above scroll containers */
        this.hoist = false;
        /**
         * Enable portal mode to render the dropdown panel in a portal outside the component's DOM tree.
         * This provides better positioning control and prevents clipping issues in complex layouts.
         */
        this.portal = false;
        this.portalManager = null;
        this.triggerDropdown = 'click';
    }
    connectedCallback() {
        super.connectedCallback();
        this.handlePanelSelect = this.handlePanelSelect.bind(this);
        this.handleKeyDown = this.handleKeyDown.bind(this);
        this.handleDocumentKeyDown = this.handleDocumentKeyDown.bind(this);
        this.handleDocumentMouseDown = this.handleDocumentMouseDown.bind(this);
        this.handleTriggerMouseEnter = this.handleTriggerMouseEnter.bind(this);
        this.handleTriggerMouseLeave = this.handleTriggerMouseLeave.bind(this);
        if (!this.containingElement) {
            this.containingElement = this;
        }
        this.emit('nile-init');
        requestAnimationFrame(() => {
            if (this.portal && !this.portalManager) {
                this.portalManager = new DropdownPortalManager(this);
            }
        });
    }
    firstUpdated() {
        this.panel.hidden = !this.open;
        if (this.triggerDropdown === 'hover') {
            const triggerEl = this.trigger;
            if (triggerEl) {
                triggerEl.addEventListener('mouseenter', this.handleTriggerMouseEnter);
                triggerEl.addEventListener('mouseleave', this.handleTriggerMouseLeave);
            }
            if (this.panel) {
                this.panel.addEventListener('mouseenter', this.handleTriggerMouseEnter);
                this.panel.addEventListener('mouseleave', this.handleTriggerMouseLeave);
            }
        }
        else {
        }
        if (this.open) {
            this.addOpenListeners();
            this.popup.active = true;
        }
    }
    handleTriggerMouseEnter() {
        clearTimeout(this.hoverTimeout);
        this.show();
    }
    handleTriggerMouseLeave() {
        clearTimeout(this.hoverTimeout);
        this.hoverTimeout = window.setTimeout(() => this.hide(), 200);
    }
    disconnectedCallback() {
        super.disconnectedCallback();
        this.removeOpenListeners();
        this.hide();
        this.emit('nile-destroy');
        if (this.portalManager) {
            this.portalManager.cleanupPortalAppend();
            this.portalManager = null;
        }
    }
    focusOnTrigger() {
        const trigger = this.trigger.assignedElements({ flatten: true })[0];
        if (typeof trigger?.focus === 'function') {
            trigger.focus();
        }
    }
    getMenu() {
        return this.panel.assignedElements({ flatten: true }).find(el => el.tagName.toLowerCase() === 'nile-menu');
    }
    handleKeyDown(event) {
        if (this.open && event.key === 'Escape') {
            event.stopPropagation();
            this.hide();
            this.focusOnTrigger();
        }
    }
    handleDocumentKeyDown(event) {
        if (event.key === 'Escape' && this.open) {
            event.stopPropagation();
            this.focusOnTrigger();
            this.hide();
            return;
        }
        if (event.key === 'Tab') {
            setTimeout(() => {
                const activeElement = this.containingElement?.getRootNode() instanceof ShadowRoot
                    ? document.activeElement?.shadowRoot?.activeElement
                    : document.activeElement;
                const hitSelf = this.containingElement && activeElement?.closest(this.containingElement.tagName.toLowerCase()) === this.containingElement;
                const hitPortalAppend = this.portal && this.portalManager?.portalContainerElement &&
                    (activeElement === this.portalManager.portalContainerElement ||
                        activeElement?.closest('.nile-dropdown-portal-append') === this.portalManager.portalContainerElement);
                if (!hitSelf && !hitPortalAppend) {
                    this.hide();
                }
            });
        }
    }
    handleDocumentMouseDown(event) {
        const path = event.composedPath();
        const hitSelf = this.containingElement && path.includes(this.containingElement);
        const hitPortalAppend = this.portal && this.portalManager?.portalContainerElement && path.includes(this.portalManager.portalContainerElement);
        if (!hitSelf && !hitPortalAppend) {
            this.hide();
        }
    }
    handlePanelSelect(event) {
        const target = event.target;
        if (!this.stayOpenOnSelect && target.tagName.toLowerCase() === 'nile-menu') {
            this.hide();
            this.focusOnTrigger();
        }
    }
    handleTriggerClick() {
        if (this.open) {
            this.hide();
        }
        else {
            this.show();
            this.focusOnTrigger();
        }
    }
    handleTriggerKeyDown(event) {
        const menu = this.getMenu();
        if (menu) {
            const menuItems = menu.getAllItems();
            const firstMenuItem = menuItems[0];
            const lastMenuItem = menuItems[menuItems.length - 1];
            if (['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(event.key)) {
                event.preventDefault();
                if (!this.open)
                    this.show();
                if (menuItems.length > 0) {
                    this.updateComplete.then(() => {
                        if (event.key === 'ArrowDown' || event.key === 'Home') {
                            menu.setCurrentItem(firstMenuItem);
                            firstMenuItem.focus();
                        }
                        if (event.key === 'ArrowUp' || event.key === 'End') {
                            menu.setCurrentItem(lastMenuItem);
                            lastMenuItem.focus();
                        }
                    });
                }
            }
        }
    }
    handleTriggerKeyUp(event) {
        if (event.key === ' ') {
            event.preventDefault();
        }
    }
    handleTriggerSlotChange() {
        this.updateAccessibleTrigger();
    }
    updateAccessibleTrigger() {
        const assignedElements = this.trigger.assignedElements({ flatten: true });
        const accessibleTrigger = assignedElements.find(el => getTabbableBoundary(el).start);
        let target;
        if (accessibleTrigger) {
            switch (accessibleTrigger.tagName.toLowerCase()) {
                case 'nile-button':
                case 'nile-icon-button':
                    target = accessibleTrigger.button;
                    break;
                default:
                    target = accessibleTrigger;
            }
            target.setAttribute('aria-haspopup', 'true');
            target.setAttribute('aria-expanded', this.open ? 'true' : 'false');
        }
    }
    /** Public methods */
    async show() {
        if (this.open)
            return;
        this.open = true;
        return waitForEvent(this, 'nile-after-show');
    }
    async hide() {
        if (!this.open)
            return;
        this.open = false;
        return waitForEvent(this, 'nile-after-hide');
    }
    reposition() {
        this.popup.reposition();
    }
    addOpenListeners() {
        this.panel.addEventListener('nile-select', this.handlePanelSelect);
        this.panel.addEventListener('keydown', this.handleKeyDown);
        document.addEventListener('keydown', this.handleDocumentKeyDown);
        document.addEventListener('mousedown', this.handleDocumentMouseDown);
    }
    removeOpenListeners() {
        if (this.panel) {
            this.panel.removeEventListener('nile-select', this.handlePanelSelect);
            this.panel.removeEventListener('keydown', this.handleKeyDown);
        }
        document.removeEventListener('keydown', this.handleDocumentKeyDown);
        document.removeEventListener('mousedown', this.handleDocumentMouseDown);
    }
    updated(changedProperties) {
        super.updated(changedProperties);
        if (changedProperties.has('portal')) {
            if (this.portal && !this.portalManager) {
                this.portalManager = new DropdownPortalManager(this);
                if (this.open) {
                    this.portalManager.setupPortalAppend();
                }
            }
            else if (!this.portal && this.portalManager) {
                this.portalManager.cleanupPortalAppend();
                this.portalManager = null;
            }
        }
    }
    async handleOpenChange() {
        if (this.disabled) {
            this.open = false;
            return;
        }
        this.updateAccessibleTrigger();
        if (this.open) {
            this.emit('nile-show');
            this.addOpenListeners();
            if (this.portal && this.portalManager) {
                this.portalManager.setupPortalAppend();
            }
            else if (this.portal && !this.portalManager) {
                this.portalManager = new DropdownPortalManager(this);
                this.portalManager.setupPortalAppend();
            }
            await stopAnimations(this);
            // Only show panel and animate if not using portal
            if (!this.portal) {
                this.panel.hidden = false;
                this.popup.active = true;
                const { keyframes, options } = getAnimation(this, 'dropdown.show', { dir: '' });
                await animateTo(this.popup.popup, keyframes, options);
            }
            this.emit('nile-after-show');
        }
        else {
            this.emit('nile-hide');
            this.removeOpenListeners();
            if (this.portal && this.portalManager) {
                this.portalManager.cleanupPortalAppend();
            }
            await stopAnimations(this);
            if (!this.portal) {
                const { keyframes, options } = getAnimation(this, 'dropdown.hide', { dir: '' });
                await animateTo(this.popup.popup, keyframes, options);
                this.panel.hidden = true;
                this.popup.active = false;
            }
            this.emit('nile-after-hide');
        }
    }
    render() {
        return html `
      <nile-popup
        part="base"
        id="sidebar-action-dropdown"
        placement=${this.placement}
        distance=${this.distance}
        skidding=${this.skidding}
        strategy=${this.hoist ? 'fixed' : 'absolute'}
        sync=${this.sync}
        flip
        shift
        auto-size="both"
        auto-size-padding="10"
        class=${classMap({
            dropdown: true,
            'dropdown--open': this.open
        })}
      >
        <slot
          name="trigger"
          slot="anchor"
          part="trigger"
          class="dropdown__trigger"
          @click=${this.handleTriggerClick}
          @keydown=${this.handleTriggerKeyDown}
          @keyup=${this.handleTriggerKeyUp}
          @slotchange=${this.handleTriggerSlotChange}
        ></slot>

        <slot
          part="panel"
          class="dropdown__panel"
          aria-hidden=${this.open ? 'false' : 'true'}
          aria-labelledby="sidebar-action-dropdown"
          style=${this.portal && this.portalManager ? 'display: none;' : ''}
        ></slot>
      </nile-popup>
    `;
    }
};
NileSideBarAction.styles = [styles];
__decorate([
    query('.dropdown')
], NileSideBarAction.prototype, "popup", void 0);
__decorate([
    query('.dropdown__trigger')
], NileSideBarAction.prototype, "trigger", void 0);
__decorate([
    query('.dropdown__panel')
], NileSideBarAction.prototype, "panel", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileSideBarAction.prototype, "open", void 0);
__decorate([
    property({ reflect: true })
], NileSideBarAction.prototype, "placement", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileSideBarAction.prototype, "disabled", void 0);
__decorate([
    property({ attribute: 'stay-open-on-select', type: Boolean, reflect: true })
], NileSideBarAction.prototype, "stayOpenOnSelect", void 0);
__decorate([
    property({ attribute: false })
], NileSideBarAction.prototype, "containingElement", void 0);
__decorate([
    property({ type: Number })
], NileSideBarAction.prototype, "distance", void 0);
__decorate([
    property({ type: Number })
], NileSideBarAction.prototype, "skidding", void 0);
__decorate([
    property()
], NileSideBarAction.prototype, "sync", void 0);
__decorate([
    property({ type: Boolean })
], NileSideBarAction.prototype, "hoist", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileSideBarAction.prototype, "portal", void 0);
__decorate([
    property({ reflect: true })
], NileSideBarAction.prototype, "triggerDropdown", void 0);
__decorate([
    watch('open', { waitUntilFirstUpdate: true })
], NileSideBarAction.prototype, "handleOpenChange", null);
NileSideBarAction = __decorate([
    customElement('nile-side-bar-action')
], NileSideBarAction);
export { NileSideBarAction };
/* Default animations */
setDefaultAnimation('dropdown.show', {
    keyframes: [
        { opacity: 0, scale: 0.9 },
        { opacity: 1, scale: 1 }
    ],
    options: { duration: 100, easing: 'ease' }
});
setDefaultAnimation('dropdown.hide', {
    keyframes: [
        { opacity: 1, scale: 1 },
        { opacity: 0, scale: 0.9 }
    ],
    options: { duration: 100, easing: 'ease' }
});
export default NileSideBarAction;
//# sourceMappingURL=nile-side-bar-action.js.map