var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { MelodicComponent } from '@melodicdev/core';
import { computePosition, autoUpdate, offset, flip, shift, arrow as arrowMiddleware } from '../../../utils/positioning/index.js';
import { dropdownTemplate } from './dropdown.template.js';
import { dropdownStyles } from './dropdown.styles.js';
/**
 * ml-dropdown - Dropdown menu component
 *
 * @example
 * ```html
 * <ml-dropdown>
 *   <ml-button slot="trigger">Options</ml-button>
 *   <ml-dropdown-item value="edit" icon="pencil">Edit</ml-dropdown-item>
 *   <ml-dropdown-item value="delete" icon="trash" destructive>Delete</ml-dropdown-item>
 * </ml-dropdown>
 * ```
 *
 * @slot trigger - The element that toggles the dropdown
 * @slot default - Menu items, groups, and separators
 * @fires ml:select - Emitted when an item is selected, detail: { value }
 * @fires ml:open - Emitted when the menu opens
 * @fires ml:close - Emitted when the menu closes
 */
let DropdownComponent = class DropdownComponent {
    constructor() {
        /** Menu placement relative to trigger */
        this.placement = 'bottom-start';
        /** Gap between trigger and menu in px */
        this.offset = 4;
        /** Show arrow pointing to trigger */
        this.arrow = false;
        /** Current open state */
        this.isOpen = false;
        this._focusedIndex = -1;
        this._cleanupAutoUpdate = null;
        /** Toggle the menu */
        this.toggle = () => {
            const menuEl = this.getMenuEl();
            if (menuEl) {
                menuEl.togglePopover();
            }
        };
        this.handleToggle = (event) => {
            const toggleEvent = event;
            if (toggleEvent.newState === 'open') {
                this.isOpen = true;
                this.startPositioning();
                this.focusFirstItem();
                this.elementRef.dispatchEvent(new CustomEvent('ml:open', { bubbles: true, composed: true }));
            }
            else {
                this.isOpen = false;
                this.clearFocus();
                this._cleanupAutoUpdate?.();
                this._cleanupAutoUpdate = null;
                this.returnFocusToTrigger();
                this.elementRef.dispatchEvent(new CustomEvent('ml:close', { bubbles: true, composed: true }));
            }
        };
        this.handleItemSelect = (event) => {
            event.stopPropagation();
            const { value } = event.detail;
            this.elementRef.dispatchEvent(new CustomEvent('ml:select', {
                bubbles: true,
                composed: true,
                detail: { value }
            }));
            this.close();
        };
        this.handleKeyDown = (event) => {
            if (!this.isOpen) {
                if (event.key === 'ArrowDown' || event.key === 'Enter' || event.key === ' ') {
                    event.preventDefault();
                    this.open();
                }
                return;
            }
            const items = this.getNavigableItems();
            if (!items.length)
                return;
            switch (event.key) {
                case 'ArrowDown':
                    event.preventDefault();
                    this.focusNextItem(items);
                    break;
                case 'ArrowUp':
                    event.preventDefault();
                    this.focusPreviousItem(items);
                    break;
                case 'Enter':
                case ' ':
                    event.preventDefault();
                    if (this._focusedIndex >= 0 && this._focusedIndex < items.length) {
                        const item = items[this._focusedIndex];
                        if (!item.disabled) {
                            item.handleClick();
                        }
                    }
                    break;
                case 'Escape':
                    event.preventDefault();
                    this.close();
                    break;
                case 'Tab':
                    this.close();
                    break;
                case 'Home':
                    event.preventDefault();
                    this.focusItemAtIndex(items, this.findFirstEnabled(items));
                    break;
                case 'End':
                    event.preventDefault();
                    this.focusItemAtIndex(items, this.findLastEnabled(items));
                    break;
                default:
                    break;
            }
        };
    }
    onCreate() {
        const menuEl = this.getMenuEl();
        if (menuEl) {
            menuEl.addEventListener('toggle', this.handleToggle);
        }
        this.elementRef.addEventListener('ml:item-select', this.handleItemSelect);
        this.elementRef.addEventListener('keydown', this.handleKeyDown);
    }
    onDestroy() {
        this._cleanupAutoUpdate?.();
        const menuEl = this.getMenuEl();
        if (menuEl) {
            menuEl.removeEventListener('toggle', this.handleToggle);
        }
        this.elementRef.removeEventListener('ml:item-select', this.handleItemSelect);
        this.elementRef.removeEventListener('keydown', this.handleKeyDown);
    }
    /** Open the menu */
    open() {
        const menuEl = this.getMenuEl();
        if (menuEl && !this.isOpen) {
            menuEl.showPopover();
        }
    }
    /** Close the menu */
    close() {
        const menuEl = this.getMenuEl();
        if (menuEl && this.isOpen) {
            menuEl.hidePopover();
        }
    }
    getNavigableItems() {
        const slot = this.elementRef.shadowRoot?.querySelector('.ml-dropdown__menu slot:not([name])');
        if (!slot)
            return [];
        const items = [];
        const assigned = slot.assignedElements();
        for (const el of assigned) {
            if (el.tagName === 'ML-DROPDOWN-ITEM') {
                items.push(el);
            }
            else if (el.tagName === 'ML-DROPDOWN-GROUP') {
                const groupSlot = el.shadowRoot?.querySelector('slot:not([name])');
                if (groupSlot) {
                    for (const child of groupSlot.assignedElements()) {
                        if (child.tagName === 'ML-DROPDOWN-ITEM') {
                            items.push(child);
                        }
                    }
                }
            }
        }
        return items;
    }
    focusFirstItem() {
        const items = this.getNavigableItems();
        const index = this.findFirstEnabled(items);
        this.focusItemAtIndex(items, index);
    }
    focusNextItem(items) {
        let index = this._focusedIndex + 1;
        while (index < items.length) {
            if (!items[index].disabled) {
                this.focusItemAtIndex(items, index);
                return;
            }
            index++;
        }
    }
    focusPreviousItem(items) {
        let index = this._focusedIndex - 1;
        while (index >= 0) {
            if (!items[index].disabled) {
                this.focusItemAtIndex(items, index);
                return;
            }
            index--;
        }
    }
    focusItemAtIndex(items, index) {
        if (index < 0)
            return;
        for (let i = 0; i < items.length; i++) {
            items[i].focused = i === index;
        }
        this._focusedIndex = index;
    }
    clearFocus() {
        const items = this.getNavigableItems();
        for (const item of items) {
            item.focused = false;
        }
        this._focusedIndex = -1;
    }
    findFirstEnabled(items) {
        return items.findIndex((item) => !item.disabled);
    }
    findLastEnabled(items) {
        for (let i = items.length - 1; i >= 0; i--) {
            if (!items[i].disabled)
                return i;
        }
        return -1;
    }
    returnFocusToTrigger() {
        const triggerSlot = this.elementRef.shadowRoot?.querySelector('slot[name="trigger"]');
        if (triggerSlot) {
            const assigned = triggerSlot.assignedElements();
            if (assigned.length > 0) {
                assigned[0].focus();
            }
        }
    }
    startPositioning() {
        const triggerEl = this.getTriggerEl();
        const menuEl = this.getMenuEl();
        if (!triggerEl || !menuEl)
            return;
        const update = () => this.updatePosition(triggerEl, menuEl);
        this._cleanupAutoUpdate?.();
        this._cleanupAutoUpdate = autoUpdate(triggerEl, menuEl, update);
    }
    updatePosition(triggerEl, menuEl) {
        const arrowEl = this.arrow ? this.elementRef.shadowRoot?.querySelector('.ml-dropdown__arrow') : null;
        const middleware = [offset(this.offset), flip(), shift({ padding: 8 })];
        if (arrowEl) {
            middleware.push(arrowMiddleware({ element: arrowEl, padding: 8 }));
        }
        const { x, y, placement, middlewareData } = computePosition(triggerEl, menuEl, {
            placement: this.placement,
            middleware
        });
        menuEl.style.left = `${x}px`;
        menuEl.style.top = `${y}px`;
        menuEl.dataset.placement = placement;
        if (arrowEl && middlewareData.arrow) {
            this.positionArrow(arrowEl, placement, middlewareData.arrow);
        }
    }
    positionArrow(arrowEl, placement, arrowData) {
        const side = placement.split('-')[0];
        arrowEl.style.left = arrowData.x === undefined ? '' : `${arrowData.x}px`;
        arrowEl.style.right = '';
        arrowEl.style.top = arrowData.y === undefined ? '' : `${arrowData.y}px`;
        arrowEl.style.bottom = '';
        if (side === 'top') {
            arrowEl.style.bottom = '-4px';
        }
        if (side === 'bottom') {
            arrowEl.style.top = '-4px';
        }
        if (side === 'left') {
            arrowEl.style.right = '-4px';
        }
        if (side === 'right') {
            arrowEl.style.left = '-4px';
        }
    }
    getTriggerEl() {
        return this.elementRef.shadowRoot?.querySelector('.ml-dropdown__trigger');
    }
    getMenuEl() {
        return this.elementRef.shadowRoot?.querySelector('.ml-dropdown__menu');
    }
};
DropdownComponent = __decorate([
    MelodicComponent({
        selector: 'ml-dropdown',
        template: dropdownTemplate,
        styles: dropdownStyles,
        attributes: ['placement', 'offset', 'arrow']
    })
], DropdownComponent);
export { DropdownComponent };
