import { __decorate } from "tslib";
import { html, nothing, } from 'lit';
import { customElement, query, state, property } from 'lit/decorators.js';
import { styles } from './nile-auto-complete.css';
import NileElement from '../internal/nile-element';
import { watch } from '../internal/watch';
import { AutoCompletePortalManager } from './portal-manager';
import { virtualize } from '@lit-labs/virtualizer/virtualize.js';
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
import { VisibilityManager } from '../utilities/visibility-manager.js';
// Define the custom element 'nile-auto-complete'
let NileAutoComplete = class NileAutoComplete extends NileElement {
    constructor() {
        super(...arguments);
        // Define component properties
        this.disabled = false;
        this.isDropdownOpen = false;
        /**
         * When true, the dropdown menu will be appended to the document body instead of the parent container.
         * This is useful when the parent has overflow: hidden, clip-path, or transform applied.
         */
        this.portal = false;
        this.portalManager = new AutoCompletePortalManager(this);
        this.enableVirtualScroll = false;
        this.openOnFocus = false;
        this.value = '';
        this.placeholder = 'Type here ..';
        this.noBorder = false;
        this.noOutline = false;
        this.noPadding = false;
        this.loading = false;
        this.filterFunction = (item, searchedValue) => item.toLowerCase().includes(searchedValue.toLowerCase());
        this.renderItemFunction = (item) => item;
        this.allMenuItems = [];
        this.enableVisibilityEffect = false;
        this.enableTabClose = false;
        this.noDropdownClose = false;
        this.label = '';
        this.menuItems = [];
        this.handleWindowResize = () => {
            this.portalManager.updatePortalAppendPosition();
        };
        this.handleWindowScroll = () => {
            this.portalManager.updatePortalAppendPosition();
        };
    }
    async firstUpdated(_changed) {
        await this.updateComplete;
        this.visibilityManager = new VisibilityManager({
            host: this,
            target: this.inputElement.input,
            enableVisibilityEffect: this.enableVisibilityEffect,
            enableTabClose: this.enableTabClose,
            isOpen: () => this.isDropdownOpen,
            onAnchorOutOfView: () => {
                this.isDropdownOpen = false;
                this.dropdownElement?.hide();
                this.emit('nile-visibility-change', {
                    visible: false,
                    reason: 'anchor-out-of-view',
                });
            },
            onDocumentHidden: () => {
                this.isDropdownOpen = false;
                this.dropdownElement?.hide();
                this.emit('nile-visibility-change', {
                    visible: false,
                    reason: 'document-hidden',
                });
            },
            emit: (event, detail) => this.emit(`nile-${event}`, detail),
        });
    }
    connectedCallback() {
        super.connectedCallback();
        this.renderItemFunction = (item) => item;
        this.handleDocumentFocusIn = this.handleDocumentFocusIn.bind(this);
        this.handleDocumentMouseDown = this.handleDocumentMouseDown.bind(this);
        this.handleWindowResize = this.handleWindowResize.bind(this);
        this.handleWindowScroll = this.handleWindowScroll.bind(this);
    }
    disconnectedCallback() {
        super.disconnectedCallback();
        this.removeOpenListeners();
        this.visibilityManager?.cleanup();
        this.portalManager.cleanupPortalAppend();
    }
    updated(changedProperties) {
        super.updated(changedProperties);
        if (changedProperties.has('allMenuItems')) {
            this.menuItems = this.applyFilter(this.allMenuItems, this.filterFunction);
            this.setVirtualMenuWidth();
            if (this.portal && this.isDropdownOpen) {
                this.portalManager.updatePortalOptions();
            }
        }
        if (changedProperties.has('isDropdownOpen')) {
            this.menuItems = this.applyFilter(this.allMenuItems, this.filterFunction);
            this.handleDropdownOpenChange();
        }
        if (changedProperties.has('value')) {
            this.menuItems = this.applyFilter(this.allMenuItems, this.filterFunction);
            if (this.portal && this.isDropdownOpen) {
                this.portalManager.updatePortalOptions();
            }
        }
        if (changedProperties.has('portal')) {
            this.handlePortalChange();
        }
    }
    handlePortalChange() {
        if (this.isDropdownOpen) {
            if (this.portal) {
                this.portalManager.setupPortalAppend();
            }
            else {
                this.portalManager.cleanupPortalAppend();
            }
        }
    }
    handleDropdownOpenChange() {
        if (this.isDropdownOpen) {
            this.addOpenListeners();
            this.visibilityManager?.setup();
            if (this.portal) {
                this.portalManager.setupPortalAppend();
            }
        }
        else {
            this.removeOpenListeners();
            this.visibilityManager?.cleanup();
            if (this.portal) {
                this.portalManager.cleanupPortalAppend();
            }
        }
    }
    addOpenListeners() {
        document.addEventListener('focusin', this.handleDocumentFocusIn);
        document.addEventListener('mousedown', this.handleDocumentMouseDown);
        if (this.portal) {
            window.addEventListener('resize', this.handleWindowResize);
            window.addEventListener('scroll', this.handleWindowScroll, true);
        }
    }
    removeOpenListeners() {
        document.removeEventListener('focusin', this.handleDocumentFocusIn);
        document.removeEventListener('mousedown', this.handleDocumentMouseDown);
        window.removeEventListener('resize', this.handleWindowResize);
        window.removeEventListener('scroll', this.handleWindowScroll, true);
    }
    handleDocumentFocusIn(event) {
        if (!this.isDropdownOpen)
            return;
        const path = event.composedPath();
        const hitSelf = path.includes(this);
        const hitDropdown = this.dropdownElement && path.includes(this.dropdownElement);
        const hitPortalAppend = this.portal && this.portalManager.portalContainerElement && path.includes(this.portalManager.portalContainerElement);
        if (!hitSelf && !hitDropdown && !hitPortalAppend) {
            this.isDropdownOpen = false;
            this.dropdownElement?.hide();
        }
    }
    handleDocumentMouseDown(event) {
        if (!this.isDropdownOpen)
            return;
        const path = event.composedPath();
        const hitSelf = path.includes(this);
        const hitDropdown = this.dropdownElement && path.includes(this.dropdownElement);
        const hitPortalAppend = this.portal && this.portalManager.portalContainerElement && path.includes(this.portalManager.portalContainerElement);
        if (!hitSelf && !hitDropdown && !hitPortalAppend) {
            this.isDropdownOpen = false;
            this.dropdownElement?.hide();
        }
    }
    render() {
        const content = this.enableVirtualScroll ? this.getVirtualizedContent() : this.getContent();
        return html `
    ${this.label
            ? html `
      <label class="nile-auto-complete__label">${this.label}</label>
    ` : nothing}
      <nile-dropdown ?disabled=${this.disabled} class="nile-dropdown--input" ?open=${this.isDropdownOpen} ?stay-open-on-select=${this.noDropdownClose} noOpenOnCLick exportparts="input, base">
        <nile-input class="nile-auto-complete--input"
          ?no-border=${this.noBorder}
          ?no-outline=${this.noOutline}
          ?no-padding=${this.noPadding}
          .disabled=${this.disabled}
          .value=${this.value}
          @nile-input=${this.handleSearch}
          @focus=${this.handleFocus}
          @click=${this.handleClick}
          slot="trigger"
          placeholder=${this.placeholder}
          exportparts="input, base"
        >
          ${this.loading ? html `<nile-icon slot="suffix" color="var(--nile-colors-primary-600)" name="var(--nile-icon-button-loading-blue-animated, var(--ng-icon-button-loading-blue-animated))" method="var(--nile-svg-method-fill, var(--ng-svg-method-stroke))" library="system"></nile-icon>` : nothing}
        </nile-input>
        ${this.menuItems.length > 0 && !this.loading
            ? content
            : nothing}
      </nile-dropdown>
    `;
    }
    getVirtualizedContent() {
        return html `
      <nile-menu class="virtualized__menu" @nile-select=${this.handleSelect} id="content-menu" exportparts="menu__items-wrapper:options__wrapper" style=${this.portal ? 'display: none;' : ''}>
        ${virtualize({
            items: this.menuItems,
            renderItem: (item) => this.getItemRenderFunction(item),
            scroller: true
        })}
      </nile-menu>
    `;
    }
    getContent() {
        return html `
      <nile-menu id="content-menu" @nile-select=${this.handleSelect} exportparts="menu__items-wrapper:options__wrapper" style=${this.portal ? 'display: none;' : ''}>
        ${this.menuItems.map((item) => this.getItemRenderFunction(item))}
      </nile-menu>`;
    }
    getItemRenderFunction(item) {
        const value = this.renderItemFunction(item);
        let strValue = "";
        if (value || typeof value === "number") {
            strValue = value.toString();
        }
        const hasTooltip = !!item.tooltip;
        const shouldShowTooltip = hasTooltip && (!item.tooltip.for || item.tooltip.for === 'menu');
        if (!shouldShowTooltip) {
            return html `
        <nile-menu-item value=${value}>${unsafeHTML(strValue)}</nile-menu-item>
      `;
        }
        let tooltipContent = null;
        const content = item.tooltip.content;
        if (content instanceof Promise) {
            tooltipContent = 'Loading...';
            content.then((resolved) => {
                item.tooltip.content = resolved;
                this.requestUpdate();
            });
        }
        else {
            tooltipContent = content;
        }
        return html `
      <nile-menu-item value=${value}>
        <nile-lite-tooltip allowHTML .content=${tooltipContent ?? ""}>
          <span class="menu-item-text">${unsafeHTML(strValue)}</span>
        </nile-lite-tooltip>
      </nile-menu-item>
    `;
    }
    handleSelect(event) {
        this.value = event.detail.value;
        this.emit('nile-complete', { value: event.detail.value });
        if (this.noDropdownClose) {
            this.isDropdownOpen = true;
            this.dropdownElement?.show();
        }
        else {
            this.isDropdownOpen = false;
            this.dropdownElement?.hide();
        }
    }
    setVirtualMenuWidth() {
        const maxLengthOption = this.menuItems
            .reduce((acc, curr) => {
            const currLength = this.renderItemFunction(curr).length;
            return acc > currLength ? acc : currLength;
        }, 0);
        const defaultWith = 110;
        const pixelMultiplier = 9.5;
        const menuWidth = maxLengthOption * pixelMultiplier < defaultWith ? defaultWith : maxLengthOption * pixelMultiplier;
        this.style.setProperty("--virtual-scroll-container-width", menuWidth + "px");
    }
    handleSearch(event) {
        this.value = event.detail.value;
        // Filter menu items based on the search value
        this.menuItems = this.applyFilter(this.allMenuItems, this.filterFunction);
        this.isDropdownOpen = this.menuItems.length > 0;
        if (this.isDropdownOpen) {
            this.dropdownElement?.show();
            if (this.portal) {
                this.portalManager.updatePortalOptions();
            }
        }
    }
    handleFocus() {
        if (!this.openOnFocus) {
            return;
        }
        if (this.portal) {
            this.inputElement?.focus();
        }
        // Delay opening the dropdown to allow focus to take effect
        setTimeout(() => {
            this.isDropdownOpen = true;
            this.dropdownElement?.show();
        }, 300);
    }
    handleClick() {
        this.isDropdownOpen = true;
        this.dropdownElement?.show();
    }
    applyFilter(list, filterFn) {
        if (typeof (list) !== 'object')
            return [];
        const res = [];
        list.forEach(el => filterFn(el, this.value) && res.push(el));
        return res;
    }
};
NileAutoComplete.styles = styles;
__decorate([
    query('nile-dropdown')
], NileAutoComplete.prototype, "dropdownElement", void 0);
__decorate([
    query('nile-input')
], NileAutoComplete.prototype, "inputElement", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileAutoComplete.prototype, "disabled", void 0);
__decorate([
    property({ type: Boolean })
], NileAutoComplete.prototype, "isDropdownOpen", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileAutoComplete.prototype, "portal", void 0);
__decorate([
    property({ type: Boolean })
], NileAutoComplete.prototype, "enableVirtualScroll", void 0);
__decorate([
    property({ type: Boolean })
], NileAutoComplete.prototype, "openOnFocus", void 0);
__decorate([
    property({ type: String })
], NileAutoComplete.prototype, "value", void 0);
__decorate([
    property({ type: String })
], NileAutoComplete.prototype, "placeholder", void 0);
__decorate([
    property({ type: Boolean })
], NileAutoComplete.prototype, "noBorder", void 0);
__decorate([
    property({ type: Boolean })
], NileAutoComplete.prototype, "noOutline", void 0);
__decorate([
    property({ type: Boolean })
], NileAutoComplete.prototype, "noPadding", void 0);
__decorate([
    property({ type: Boolean })
], NileAutoComplete.prototype, "loading", void 0);
__decorate([
    property({ attribute: false })
], NileAutoComplete.prototype, "filterFunction", void 0);
__decorate([
    property({ attribute: false })
], NileAutoComplete.prototype, "renderItemFunction", void 0);
__decorate([
    property({ type: Array })
], NileAutoComplete.prototype, "allMenuItems", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileAutoComplete.prototype, "enableVisibilityEffect", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileAutoComplete.prototype, "enableTabClose", void 0);
__decorate([
    property({ type: Boolean, reflect: true, attribute: true })
], NileAutoComplete.prototype, "noDropdownClose", void 0);
__decorate([
    property({ type: String })
], NileAutoComplete.prototype, "label", void 0);
__decorate([
    state()
], NileAutoComplete.prototype, "menuItems", void 0);
__decorate([
    watch('portal', { waitUntilFirstUpdate: true })
], NileAutoComplete.prototype, "handlePortalChange", null);
NileAutoComplete = __decorate([
    customElement('nile-auto-complete')
], NileAutoComplete);
export { NileAutoComplete };
export default NileAutoComplete;
//# sourceMappingURL=nile-auto-complete.js.map