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, offset, flip, shift } from '../../../utils/positioning/index.js';
import { selectTemplate } from './select.template.js';
import { selectStyles } from './select.styles.js';
/**
 * ml-select - Custom select/dropdown component
 *
 * @example
 * ```html
 * <ml-select
 *   label="Country"
 *   placeholder="Select a country"
 *   .options=${[
 *     { value: 'us', label: 'United States' },
 *     { value: 'ca', label: 'Canada' },
 *     { value: 'mx', label: 'Mexico' }
 *   ]}
 * ></ml-select>
 *
 * <ml-select
 *   label="Countries"
 *   placeholder="Select countries"
 *   multiple
 *   .values=${['us', 'ca']}
 *   .options=${[
 *     { value: 'us', label: 'United States' },
 *     { value: 'ca', label: 'Canada' },
 *     { value: 'mx', label: 'Mexico' }
 *   ]}
 * ></ml-select>
 * ```
 *
 * @fires ml:change - Emitted when selection changes
 * @fires ml:open - Emitted when dropdown opens
 * @fires ml:close - Emitted when dropdown closes
 */
let SelectComponent = class SelectComponent {
    constructor() {
        /** Label text */
        this.label = '';
        /** Placeholder text when no selection */
        this.placeholder = 'Select an option';
        /** Hint text shown below select */
        this.hint = '';
        /** Error message (shows error state when set) */
        this.error = '';
        /** Select size */
        this.size = 'md';
        /** Disable the select */
        this.disabled = false;
        /** Mark as required */
        this.required = false;
        /** Enable multi-select mode */
        this.multiple = false;
        /** Currently selected value */
        this.value = '';
        /** Currently selected values (multi-select) */
        this.values = [];
        /** Available options */
        this.options = [];
        /** Search query for inline filtering */
        this.search = '';
        /** Whether dropdown is open */
        this.isOpen = false;
        /** Currently focused option index for keyboard navigation */
        this.focusedIndex = -1;
        /** Bound event handlers for cleanup */
        this._handleKeyDown = this.onKeyDown.bind(this);
        this._handlePopoverToggle = this.onPopoverToggle.bind(this);
        this._handleScroll = null;
        this._lastCloseTime = 0;
        this._syncingValues = false;
        /** Toggle dropdown open/close */
        this.toggle = () => {
            if (this.disabled)
                return;
            if (this.multiple) {
                if (!this.isOpen) {
                    this.open();
                }
                return;
            }
            if (this.isOpen) {
                this.close();
            }
            else if (Date.now() - this._lastCloseTime > 150) {
                this.open();
            }
        };
        /** Open the dropdown */
        this.open = () => {
            if (this.disabled || this.isOpen)
                return;
            this.getDropdownEl()?.showPopover();
        };
        /** Close the dropdown */
        this.close = () => {
            if (!this.isOpen)
                return;
            this.getDropdownEl()?.hidePopover();
        };
        /** Select an option */
        this.selectOption = (option) => {
            if (option.disabled)
                return;
            if (this.multiple) {
                this.toggleOption(option);
                return;
            }
            this.value = option.value;
            this.close();
            this.elementRef.dispatchEvent(new CustomEvent('ml:change', {
                bubbles: true,
                composed: true,
                detail: { value: this.value, option }
            }));
        };
        /** Handle click on option */
        this.handleOptionClick = (event, option) => {
            event.stopPropagation();
            this.selectOption(option);
        };
        this.handleTagRemove = (event, value) => {
            event.stopPropagation();
            if (this.disabled)
                return;
            this.values = this.values.filter((item) => item !== value);
            this.elementRef.dispatchEvent(new CustomEvent('ml:change', {
                bubbles: true,
                composed: true,
                detail: { values: [...this.values], options: this.selectedOptions }
            }));
        };
        this.handleSearchInput = (event) => {
            if (this.disabled)
                return;
            const target = event.target;
            this.search = target.value;
            this.focusedIndex = this.findFirstEnabledIndex();
            if (!this.isOpen) {
                this.open();
            }
        };
        this.handleSearchClick = (event) => {
            event.stopPropagation();
            if (!this.isOpen) {
                this.open();
            }
        };
    }
    onCreate() {
        this.elementRef.addEventListener('keydown', this._handleKeyDown);
        this.getDropdownEl()?.addEventListener('toggle', this._handlePopoverToggle);
    }
    onDestroy() {
        this.elementRef.removeEventListener('keydown', this._handleKeyDown);
        this.removeScrollListener();
        this.getDropdownEl()?.removeEventListener('toggle', this._handlePopoverToggle);
    }
    onPropertyChange(name) {
        if (this._syncingValues) {
            return;
        }
        if (name === 'multiple') {
            if (this.multiple) {
                if (!this.values.length && this.value) {
                    this.updateValues([this.value]);
                }
                return;
            }
            if (this.values.length) {
                this.value = this.values[0] ?? '';
            }
            this.updateValues([]);
            this.search = '';
            return;
        }
        if (name === 'values') {
            const rawValues = this.values;
            let normalized = [];
            if (typeof rawValues === 'string') {
                normalized = rawValues
                    .split(',')
                    .map((value) => value.trim())
                    .filter((value) => value.length > 0);
            }
            else if (Array.isArray(rawValues)) {
                normalized = rawValues.filter((value) => typeof value === 'string');
            }
            normalized = Array.from(new Set(normalized));
            if (!this.areValuesEqual(this.values, normalized)) {
                this.updateValues(normalized);
            }
            if (!this.multiple) {
                this.value = normalized[0] ?? '';
                this.updateValues([]);
            }
            return;
        }
        if (name === 'value' && this.multiple) {
            if (this.value) {
                const nextValues = Array.from(new Set([...this.values, this.value]));
                if (!this.areValuesEqual(this.values, nextValues)) {
                    this.updateValues(nextValues);
                }
            }
        }
    }
    /** Get the currently selected option */
    get selectedOption() {
        return this.options.find((opt) => opt.value === this.value);
    }
    /** Get the currently selected options (multi-select) */
    get selectedOptions() {
        if (!this.multiple) {
            return this.selectedOption ? [this.selectedOption] : [];
        }
        return this.options.filter((opt) => this.values.includes(opt.value));
    }
    /** Get display text for trigger */
    get displayText() {
        if (this.multiple) {
            return this.selectedOptions.map((option) => option.label).join(', ');
        }
        return this.selectedOption?.label || '';
    }
    get filteredOptions() {
        const query = this.search.trim().toLowerCase();
        if (!query)
            return this.options;
        return this.options.filter((option) => {
            const labelMatch = option.label.toLowerCase().includes(query);
            const valueMatch = option.value.toLowerCase().includes(query);
            return labelMatch || valueMatch;
        });
    }
    get hasValue() {
        return this.multiple ? this.values.length > 0 : !!this.value;
    }
    /** Toggle a value in multi-select mode */
    toggleOption(option) {
        const exists = this.values.includes(option.value);
        this.values = exists ? this.values.filter((value) => value !== option.value) : [...this.values, option.value];
        this.elementRef.dispatchEvent(new CustomEvent('ml:change', {
            bubbles: true,
            composed: true,
            detail: { values: [...this.values], options: this.selectedOptions, option }
        }));
    }
    /** Handle popover toggle events (open/close via Popover API) */
    onPopoverToggle(event) {
        const toggleEvent = event;
        if (toggleEvent.newState === 'open') {
            this.isOpen = true;
            this.focusedIndex = this.getInitialFocusIndex();
            this.positionDropdown();
            this.addScrollListener();
            this.elementRef.dispatchEvent(new CustomEvent('ml:open', { bubbles: true, composed: true }));
        }
        else {
            this.isOpen = false;
            this.focusedIndex = -1;
            this.search = '';
            this._lastCloseTime = Date.now();
            this.removeScrollListener();
            this.elementRef.dispatchEvent(new CustomEvent('ml:close', { bubbles: true, composed: true }));
        }
    }
    /** Position the dropdown relative to the trigger using fixed positioning */
    positionDropdown() {
        const triggerEl = this.elementRef.shadowRoot?.querySelector('.ml-select__trigger');
        const dropdownEl = this.getDropdownEl();
        if (!triggerEl || !dropdownEl)
            return;
        dropdownEl.style.width = `${triggerEl.offsetWidth}px`;
        const { x, y } = computePosition(triggerEl, dropdownEl, {
            placement: 'bottom-start',
            middleware: [offset(4), flip(), shift({ padding: 8 })]
        });
        dropdownEl.style.left = `${x}px`;
        dropdownEl.style.top = `${y}px`;
    }
    /** Close dropdown when any ancestor scrolls */
    addScrollListener() {
        this._handleScroll = (event) => {
            const dropdownEl = this.getDropdownEl();
            if (dropdownEl?.contains(event.target))
                return;
            this.close();
        };
        window.addEventListener('scroll', this._handleScroll, true);
    }
    removeScrollListener() {
        if (this._handleScroll) {
            window.removeEventListener('scroll', this._handleScroll, true);
            this._handleScroll = null;
        }
    }
    getDropdownEl() {
        return this.elementRef.shadowRoot?.querySelector('.ml-select__dropdown');
    }
    /** Handle keyboard navigation */
    onKeyDown(event) {
        if (this.disabled)
            return;
        const target = event.target;
        const isSearchInput = target?.classList?.contains('ml-select__search') ?? false;
        switch (event.key) {
            case 'Enter':
            case ' ':
                if (isSearchInput)
                    return;
                event.preventDefault();
                if (this.isOpen && this.focusedIndex >= 0) {
                    const option = this.getActiveOptions()[this.focusedIndex];
                    if (option && !option.disabled) {
                        this.selectOption(option);
                    }
                }
                else {
                    this.toggle();
                }
                break;
            case 'Escape':
                event.preventDefault();
                this.close();
                break;
            case 'ArrowDown':
                event.preventDefault();
                if (!this.isOpen) {
                    this.open();
                }
                else {
                    this.focusNextOption();
                }
                break;
            case 'ArrowUp':
                event.preventDefault();
                if (this.isOpen) {
                    this.focusPreviousOption();
                }
                break;
            case 'Home':
                event.preventDefault();
                if (this.isOpen) {
                    this.focusedIndex = this.findFirstEnabledIndex();
                }
                break;
            case 'End':
                event.preventDefault();
                if (this.isOpen) {
                    this.focusedIndex = this.findLastEnabledIndex();
                }
                break;
            case 'Tab':
                this.close();
                break;
            default:
                break;
        }
    }
    /** Move focus to next enabled option */
    focusNextOption() {
        const startIndex = this.focusedIndex;
        let index = startIndex + 1;
        const options = this.getActiveOptions();
        while (index < options.length) {
            if (!options[index].disabled) {
                this.focusedIndex = index;
                return;
            }
            index++;
        }
    }
    /** Move focus to previous enabled option */
    focusPreviousOption() {
        const startIndex = this.focusedIndex;
        let index = startIndex - 1;
        const options = this.getActiveOptions();
        while (index >= 0) {
            if (!options[index].disabled) {
                this.focusedIndex = index;
                return;
            }
            index--;
        }
    }
    /** Find first enabled option index */
    findFirstEnabledIndex() {
        return this.getActiveOptions().findIndex((opt) => !opt.disabled);
    }
    /** Find last enabled option index */
    findLastEnabledIndex() {
        const options = this.getActiveOptions();
        for (let i = options.length - 1; i >= 0; i--) {
            if (!options[i].disabled) {
                return i;
            }
        }
        return -1;
    }
    getInitialFocusIndex() {
        const options = this.getActiveOptions();
        if (this.multiple && this.values.length > 0) {
            const selectedIndex = options.findIndex((opt) => this.values.includes(opt.value) && !opt.disabled);
            if (selectedIndex >= 0) {
                return selectedIndex;
            }
        }
        if (!this.multiple && this.value) {
            const selectedIndex = options.findIndex((opt) => opt.value === this.value && !opt.disabled);
            if (selectedIndex >= 0) {
                return selectedIndex;
            }
        }
        return this.findFirstEnabledIndex();
    }
    getActiveOptions() {
        return this.filteredOptions;
    }
    updateValues(values) {
        this._syncingValues = true;
        this.values = values;
        this._syncingValues = false;
    }
    areValuesEqual(left, right) {
        if (left.length !== right.length)
            return false;
        for (let i = 0; i < left.length; i++) {
            if (left[i] !== right[i])
                return false;
        }
        return true;
    }
};
SelectComponent = __decorate([
    MelodicComponent({
        selector: 'ml-select',
        template: selectTemplate,
        styles: selectStyles,
        attributes: ['label', 'placeholder', 'hint', 'error', 'size', 'disabled', 'required', 'value', 'multiple']
    })
], SelectComponent);
export { SelectComponent };
