/**
 * @license
 * Copyright Tyler Technologies, Inc. 
 * License: Apache-2.0
 */
import { deepQuerySelectorAll, getActiveElement, toggleAttribute } from '@tylertech/forge-core';
import { BaseAdapter } from '../core/base/base-adapter';
import { AUTOCOMPLETE_CONSTANTS } from './autocomplete-constants';
import { TEXT_FIELD_CONSTANTS } from '../text-field';
import { ListDropdown } from '../list-dropdown';
import { CHIP_FIELD_CONSTANTS } from '../chip-field';
import { POPOVER_CONSTANTS } from '../popover';
import { setAriaControls, tryCreateAriaControlsPlaceholder } from '../core/utils/utils';
/**
 * The DOM adapter for the `<forge-autocomplete>` element.
 */
export class AutocompleteAdapter extends BaseAdapter {
    constructor(component) {
        super(component);
        this.setInputElement();
    }
    get inputElement() {
        return this._inputElement;
    }
    setInputElement() {
        const inputElements = deepQuerySelectorAll(this._component, AUTOCOMPLETE_CONSTANTS.selectors.INPUT, false);
        if (inputElements.length) {
            this._inputElement = inputElements[0];
        }
        return this._inputElement;
    }
    setInputAttribute(name, value) {
        this._inputElement.setAttribute(name, value);
    }
    addInputListener(type, listener) {
        this._inputElement.addEventListener(type, listener);
    }
    removeInputListener(type, listener) {
        this._inputElement.removeEventListener(type, listener);
    }
    initializeInputAccessibility(identifier) {
        this._inputElement.setAttribute('autocomplete', 'off');
        this._inputElement.setAttribute('role', 'combobox');
        this._inputElement.setAttribute('aria-live', 'polite');
        this._inputElement.setAttribute('aria-atomic', 'true');
        this._inputElement.setAttribute('aria-haspopup', 'true');
        this._inputElement.setAttribute('aria-expanded', 'false');
        this._inputElement.setAttribute('aria-autocomplete', 'list');
        tryCreateAriaControlsPlaceholder();
        setAriaControls(this._inputElement);
    }
    isWrappingChipField() {
        return !!this._component.querySelector(CHIP_FIELD_CONSTANTS.elementName);
    }
    show(config, popupTarget) {
        this._targetElement = this._getTargetElement(popupTarget);
        if (!this._targetElement) {
            return;
        }
        this._listDropdown = new ListDropdown(this._targetElement, config);
        this._listDropdown.open();
        this._inputElement.setAttribute('aria-expanded', 'true');
        this._inputElement.setAttribute('aria-controls', `list-dropdown-popup-${config.id}`);
        this._tryToggleDropdownIconRotation(true);
    }
    async hide(listener, { destroy = false } = {}) {
        this.setBusyVisibility(false);
        this._tryToggleDropdownIconRotation(false);
        this._inputElement?.removeAttribute('aria-activedescendant');
        this._inputElement?.removeAttribute('aria-controls');
        this._inputElement?.setAttribute('aria-expanded', 'false');
        if (!this._listDropdown) {
            return;
        }
        const { anchorElement } = this._listDropdown.dropdownElement;
        if (anchorElement && anchorElement instanceof HTMLElement) {
            anchorElement?.removeEventListener(POPOVER_CONSTANTS.events.TOGGLE, listener);
        }
        if (destroy) {
            this._listDropdown.destroy();
        }
        else {
            await this._listDropdown.close();
        }
        this._listDropdown = undefined;
    }
    setBusyVisibility(isVisible) {
        this._listDropdown?.setBusyVisibility(isVisible);
    }
    setDismissListener(listener) {
        if (!this._listDropdown || !this._listDropdown.dropdownElement) {
            return;
        }
        const dropdownElement = this._listDropdown.dropdownElement;
        if (dropdownElement.anchorElement && dropdownElement.anchorElement instanceof HTMLElement) {
            dropdownElement.anchorElement.addEventListener(POPOVER_CONSTANTS.events.TOGGLE, listener);
        }
    }
    focus() {
        window.requestAnimationFrame(() => this._inputElement.focus());
    }
    setOptions(options) {
        this._listDropdown?.setOptions(options);
    }
    appendOptions(options) {
        this._listDropdown?.appendOptions(options);
    }
    setSelectedText(value) {
        this._inputElement.value = value;
    }
    getInputValue() {
        return this._inputElement.value;
    }
    setInputValue(value) {
        this._inputElement.value = value;
    }
    selectInputValue() {
        window.requestAnimationFrame(() => this._inputElement.select());
    }
    isFocusWithinPopup(target) {
        if (!this._listDropdown || !this._listDropdown.dropdownElement) {
            return false;
        }
        return this._listDropdown.dropdownElement.contains(target);
    }
    hasFocus() {
        const activeElement = getActiveElement(this._component.ownerDocument);
        return activeElement === this._inputElement || this.isFocusWithinPopup(activeElement);
    }
    hasInputElement() {
        return !!this._inputElement;
    }
    setDropdownIconListener(type, listener) {
        window.requestAnimationFrame(() => {
            const dropdownIcon = this._component.querySelector(AUTOCOMPLETE_CONSTANTS.selectors.DROPDOWN_ICON);
            if (dropdownIcon) {
                dropdownIcon.addEventListener(type, listener);
            }
        });
    }
    removeDropdownIconListener(type, listener) {
        const dropdownIcon = this._component.querySelector(AUTOCOMPLETE_CONSTANTS.selectors.DROPDOWN_ICON);
        if (dropdownIcon) {
            dropdownIcon.removeEventListener(type, listener);
        }
    }
    setClearButtonListener(type, listener) {
        window.requestAnimationFrame(() => {
            const textField = this._component.querySelector(TEXT_FIELD_CONSTANTS.elementName);
            if (textField && (textField.showClear || textField.hasAttribute(TEXT_FIELD_CONSTANTS.attributes.SHOW_CLEAR))) {
                this._component.addEventListener(TEXT_FIELD_CONSTANTS.events.CLEAR, listener);
            }
            const clearButton = this._component.querySelector(AUTOCOMPLETE_CONSTANTS.selectors.CLEAR_BUTTON);
            if (clearButton) {
                clearButton.addEventListener(type, listener);
            }
        });
    }
    removeClearButtonListener(type, listener) {
        this._component.removeEventListener(TEXT_FIELD_CONSTANTS.events.CLEAR, listener);
        const clearButton = this._component.querySelector(AUTOCOMPLETE_CONSTANTS.selectors.CLEAR_BUTTON);
        clearButton?.removeEventListener(type, listener);
    }
    propagateKey(key) {
        this._listDropdown?.handleKey(key);
    }
    updateActiveDescendant(id) {
        if (!this._targetElement) {
            return;
        }
        toggleAttribute(this._inputElement, !!id, 'aria-activedescendant', id);
    }
    getTargetElementWidth(selector) {
        if (!this._targetElement) {
            this._targetElement = this._getTargetElement(selector);
        }
        return this._targetElement.getBoundingClientRect().width;
    }
    getPopupElement() {
        return this._listDropdown?.dropdownElement ?? null;
    }
    activateFirstOption() {
        this._listDropdown?.activateFirstOption();
    }
    activateSelectedOption() {
        this._listDropdown?.activateSelectedOption();
    }
    activateOptionByIndex(value) {
        this._listDropdown?.activateOption(value);
    }
    getActiveOptionIndex() {
        return this._listDropdown?.getActiveOptionIndex() ?? null;
    }
    clearActiveOption() {
        this._listDropdown?.clearActiveOption();
    }
    setSelectedOptions(options) {
        if (this._listDropdown) {
            const values = options.map(o => o.value);
            this._listDropdown.setSelectedValues(values);
        }
    }
    queueDropdownPositionUpdate() {
        if (!this.getPopupElement()) {
            return;
        }
        // We need to wait for the next animation frame to ensure that the layout has been updated
        window.requestAnimationFrame(() => {
            const dropdownEl = this.getPopupElement();
            dropdownEl?.position();
        });
    }
    _getTargetElement(selector) {
        return selector ? this._component.querySelector(selector) || this._getDefaultTargetElement() : this._getDefaultTargetElement();
    }
    _getDefaultTargetElement() {
        // This component is often used with the field-like Forge elements, if so, let's target our popup
        // around one if its internal elements for proper alignment
        const fieldLike = this._tryGetFieldLikeChild();
        if (fieldLike?.popoverTargetElement) {
            return fieldLike.popoverTargetElement;
        }
        return this._component.querySelector('input') || this._component;
    }
    _tryToggleDropdownIconRotation(state) {
        const fieldLike = this._tryGetFieldLikeChild();
        if (fieldLike?.popoverIcon) {
            fieldLike.popoverExpanded = state;
        }
        // Deprecated/legacy support
        // TODO: Remove in a future release
        const dropdownIcon = this._component.querySelector(AUTOCOMPLETE_CONSTANTS.selectors.DROPDOWN_ICON);
        if (dropdownIcon) {
            dropdownIcon.style.transition = 'transform 120ms linear';
            dropdownIcon.style.transform = state ? 'rotateZ(180deg)' : '';
        }
    }
    _tryGetFieldLikeChild() {
        const fieldLikeElements = [TEXT_FIELD_CONSTANTS.elementName, CHIP_FIELD_CONSTANTS.elementName];
        return this._component.querySelector(`:is(${fieldLikeElements.join(',')})`);
    }
}
