/**
 * @license
 * Copyright 2023 Tyler Technologies, Inc. 
 * License: Apache-2.0
 */
import { LIST_DROPDOWN_CONSTANTS } from './list-dropdown-constants';
import { createDropdown, createList, createListItems, createAsyncElement, createBusyElement, createCheckboxElement } from './list-dropdown-utils';
import { POPUP_CONSTANTS } from '../popup';
import { LIST_ITEM_CONSTANTS } from '../list/list-item';
import { ScrollEvents, getShadowElement, ScrollAxisObserver, removeAllChildren, isFunction, removeElement, replaceElement, createVisuallyHiddenElement, isDeepEqual, tryScrollIntoView } from '@tylertech/forge-core';
import { ICON_CONSTANTS } from '../icon';
export class ListDropdownAdapter {
    constructor(_targetElement) {
        this._targetElement = _targetElement;
    }
    get dropdownElement() {
        return this._dropdownElement;
    }
    open(config, selectCallback, closeCb) {
        // Now lets create the popup and append the children
        this._dropdownElement = createDropdown(config, this._targetElement);
        this.syncWidth(!!config.syncWidth, config.targetWidthCallback);
        // If we are configured to show a busy indicator (linear progress bar across the top), then create and append it first
        if (config.allowBusy) {
            this._busyElement = createBusyElement();
            this._busyElement.style.display = 'none';
            this._dropdownElement.appendChild(this._busyElement);
        }
        // Create the header element if a builder exists
        if (config.headerBuilder) {
            this._headerElement = config.headerBuilder();
            if (this._headerElement) {
                this._headerElement.setAttribute(LIST_DROPDOWN_CONSTANTS.attributes.DATA_ALLOW_FOCUS, '');
            }
        }
        // Create the footer element if a builder exists
        if (config.footerBuilder) {
            this._footerElement = config.footerBuilder();
            if (this._footerElement) {
                this._footerElement.setAttribute(LIST_DROPDOWN_CONSTANTS.attributes.DATA_ALLOW_FOCUS, '');
            }
        }
        // Create the list from our config
        this._listElement = createList(config);
        // Add the listener for when list items are selected from the dropdown
        this._listElement.addEventListener(LIST_ITEM_CONSTANTS.events.SELECT, (evt) => {
            evt.detail.listItem.setAttribute('aria-selected', 'true');
            selectCallback(evt.detail.value, evt.detail.listItem.id);
        });
        // Determine if we need to show the list or the async element first
        if (config.options.length) {
            // Now we can create an append the list items
            createListItems(config, this._listElement);
            this._dropdownElement.appendChild(this._listElement);
            // Always append the optional header element **first**
            if (this._headerElement) {
                this._dropdownElement.insertAdjacentElement('afterbegin', this._headerElement);
            }
            // Always append the optional footer element **last**
            if (this._footerElement) {
                this._dropdownElement.appendChild(this._footerElement);
            }
        }
        else if (config.allowBusy) {
            this._asyncElement = createAsyncElement(config.asyncStyle);
            this._dropdownElement.appendChild(this._asyncElement);
        }
        // Create the announcer element for a11y
        this._announcerElement = createVisuallyHiddenElement();
        this._announcerElement.id = `${config.id}-activedescendant`;
        this._dropdownElement.appendChild(this._announcerElement);
        // Open the popup
        this._dropdownElement.open = true;
    }
    close() {
        if (!this._dropdownElement) {
            return;
        }
        this._dropdownElement.open = false;
        this._dropdownElement = undefined;
        this._listElement = undefined;
        this._announcerElement = undefined;
    }
    setScrollBottomListener(listener, scrollThreshold) {
        if (this._dropdownElement) {
            if (!this._scrollObserver) {
                const scrollTarget = getShadowElement(this._dropdownElement, POPUP_CONSTANTS.selectors.CONTAINER);
                const scrollConfig = { scrollThreshold };
                this._scrollObserver = new ScrollAxisObserver(scrollTarget, scrollConfig);
                this._scrollObserver.addListener(ScrollEvents.ScrolledEnd, listener);
            }
        }
    }
    removeScrollBottomListener(listener) {
        if (this._scrollObserver) {
            this._scrollObserver.removeListener(ScrollEvents.ScrolledEnd, listener);
        }
    }
    getActiveOptionIndex() {
        if (!this._dropdownElement) {
            return -1;
        }
        const listItems = this._getListItemElements();
        const activeListItem = [...listItems].reverse().find(li => li.active);
        return activeListItem ? listItems.indexOf(activeListItem) : -1;
    }
    getSelectedOptionIndex() {
        const listItems = this._getListItemElements();
        return listItems.findIndex(li => li.selected);
    }
    getActiveOptionIdByIndex(index) {
        if (!this._dropdownElement) {
            return null;
        }
        const listItems = this._getListItemElements();
        const item = listItems[index];
        return item ? item.id : null;
    }
    toggleOptionMultiple(index, isSelected) {
        if (!this._dropdownElement) {
            return;
        }
        const listItems = this._getListItemElements();
        if (listItems.length && listItems[index]) {
            this._toggleSelectedOption(listItems[index], isSelected);
        }
    }
    scrollOptionIntoView(index, animate = true) {
        const listItem = this._getListItemElements()[index];
        if (listItem) {
            this._scrollListItemIntoView(listItem, animate ? 'smooth' : 'auto', 'center');
        }
    }
    scrollSelectedOptionIntoView(animate = true) {
        const listItem = this._getSelectedListItem();
        this._scrollListItemIntoView(listItem, animate ? 'smooth' : 'auto', 'center');
    }
    activateSelectedOption(config) {
        const listItems = this._getListItemElements();
        if (listItems.length) {
            const activeListItems = listItems.filter(li => li.active);
            activeListItems.forEach(li => li.active = false);
        }
        const listItem = this._getSelectedListItem();
        if (listItem) {
            this._activateListOption(listItem, config.activeChangeCallback);
        }
    }
    activateOption(index, activeChangeCallback, animate = true) {
        if (!this._dropdownElement) {
            return;
        }
        const listItems = this._getListItemElements();
        if (listItems.length) {
            const activeListItems = listItems.filter(li => li.active);
            activeListItems.forEach(li => li.active = false);
            this._activateListOption(listItems[index], activeChangeCallback);
            this._scrollListItemIntoView(listItems[index], animate ? 'smooth' : 'auto');
        }
    }
    setSelectedValues(values, multiple = false) {
        if (!this._dropdownElement) {
            return;
        }
        const listItems = this._getListItemElements();
        for (const listItem of listItems) {
            const isSelected = values.some(v => isDeepEqual(v, listItem.value));
            listItem.selected = isSelected;
            if (multiple) {
                const checkboxElement = listItem.querySelector(`[${LIST_DROPDOWN_CONSTANTS.attributes.CHECKBOX_ELEMENT}]`);
                if (checkboxElement) {
                    const newCheckboxElement = createCheckboxElement(isSelected);
                    replaceElement(newCheckboxElement, checkboxElement);
                }
            }
        }
    }
    clearActiveOption() {
        const listItems = this._getListItemElements();
        listItems.forEach(li => li.active = false);
    }
    syncWidth(sync, targetWidthCallback) {
        if (this._dropdownElement) {
            this._dropdownElement.style[sync ? 'width' : 'minWidth'] = `${this._getTargetElementWidth(targetWidthCallback)}px`;
        }
    }
    setOptions(config) {
        if (!this._dropdownElement || !this._listElement) {
            return;
        }
        if (this._asyncElement && this._asyncElement.isConnected) {
            removeElement(this._asyncElement);
        }
        if (this._busyElement) {
            this._busyElement.close();
        }
        if (!this._listElement.isConnected) {
            this._dropdownElement.appendChild(this._listElement);
        }
        removeAllChildren(this._listElement);
        createListItems(config, this._listElement);
        if (this._headerElement && !this._headerElement.isConnected) {
            this._dropdownElement.insertAdjacentElement('afterbegin', this._headerElement);
        }
        if (this._footerElement && !this._footerElement.isConnected) {
            this._dropdownElement.insertAdjacentElement('beforeend', this._footerElement);
        }
        if ('position' in this._dropdownElement && typeof this._dropdownElement.position === 'function') {
            this._dropdownElement.position();
        }
    }
    appendOptions(options, config) {
        if (!this._dropdownElement || !this._listElement) {
            return;
        }
        createListItems(config, this._listElement, options, this._listElement.childElementCount, false);
    }
    setBusyVisibility(isVisible) {
        if (!this._dropdownElement) {
            return;
        }
        if (isVisible) {
            this._busyElement.style.removeProperty('display');
            this._busyElement.open();
        }
        else {
            this._busyElement.close();
        }
    }
    getScreenWidth() {
        return window.innerWidth;
    }
    _getListItemElements() {
        return this._dropdownElement ? Array.from(this._dropdownElement.querySelectorAll(LIST_ITEM_CONSTANTS.elementName)) : [];
    }
    _toggleSelectedOption(listItem, isSelected) {
        if (!this._dropdownElement) {
            return;
        }
        // First we need to remove the active state from any other list items
        const listItems = this._getListItemElements();
        if (listItems.length) {
            const activeItems = listItems.filter(li => li !== listItem && li.active);
            if (activeItems.length) {
                activeItems.forEach(ai => ai.active = false);
            }
        }
        // Now we can toggle the selected state and sync the active state
        listItem.selected = isSelected;
        listItem.setAttribute('aria-selected', `${isSelected}`);
        listItem.setAttribute('aria-checked', `${isSelected}`);
        if (isSelected) {
            listItem.active = true;
        }
        // Toggle the checkbox icon based on the selected state
        const checkboxElement = listItem.querySelector(`${ICON_CONSTANTS.elementName}[slot=leading]`);
        if (checkboxElement) {
            const newCheckboxElement = createCheckboxElement(isSelected);
            replaceElement(newCheckboxElement, checkboxElement);
        }
    }
    _getTargetElementWidth(cb) {
        if (cb && isFunction(cb)) {
            return cb();
        }
        return this._targetElement.getBoundingClientRect().width;
    }
    _activateListOption(listItem, activeChangeCallback) {
        if (listItem && !listItem.disabled) {
            listItem.active = true;
            if (activeChangeCallback && isFunction(activeChangeCallback)) {
                activeChangeCallback(listItem.id);
            }
        }
    }
    _scrollListItemIntoView(listItem, behavior = 'auto', block = 'nearest') {
        if (listItem && this._dropdownElement && this._dropdownElement.isConnected) {
            const scrollContainer = getShadowElement(this._dropdownElement, POPUP_CONSTANTS.selectors.CONTAINER);
            if (scrollContainer) {
                tryScrollIntoView(scrollContainer, listItem, behavior, block);
            }
        }
    }
    _getSelectedListItem() {
        const listItems = this._getListItemElements();
        return listItems.find(li => li.selected);
    }
}
