import { h, Host } from "@stencil/core";
import { cls, getId, isEmpty } from "../../utils/helpers";
import { autoUpdate, computePosition, flip, offset, shift, size } from "@floating-ui/dom";
import { Lang } from "../../services/lang";
export class XSelect {
    constructor() {
        /**
         * Element ID for internal reference
         */
        this.inputId = getId('select');
        this.label = undefined;
        this.name = undefined;
        this.placeholder = undefined;
        this.info = undefined;
        this.required = undefined;
        this.loading = undefined;
        this.autofocus = undefined;
        this.multiple = undefined;
        this.size = undefined;
        this.width = undefined;
        this.autocomplete = 'off';
        this.value = '';
        this.isValid = true;
        this.isFocused = undefined;
        this.isLoading = undefined;
        this.isDisabled = undefined;
        this.isFiltered = undefined;
        this.computedValue = [];
        this.computedText = [];
        this.filteredCount = undefined;
        this.filteredTotal = undefined;
    }
    /**
     * Watch changes in value property
     */
    watchValue(newValue) {
        var _a;
        this.selectOptionByValue(newValue);
        this.el.dispatchEvent(new InputEvent('input', { bubbles: true }));
        this.formValidateCallback(this.isReady);
        (_a = this.internals.form) === null || _a === void 0 ? void 0 : _a.dispatchEvent(new InputEvent('input', { bubbles: false }));
        if (!this.isReady) {
            this.isReady = true;
        }
    }
    /**
     * on child option element is triggered the selection
     */
    handleOptionSelected(ev) {
        if (this.multiple) {
            this.computedValue.includes(ev.detail.value) ?
                this.computedValue.splice(this.computedValue.indexOf(ev.detail.value), 1) :
                this.computedValue.push(ev.detail.value);
            this.computedText.includes(ev.detail.text) ?
                this.computedText.splice(this.computedText.indexOf(ev.detail.text), 1) :
                this.computedText.push(ev.detail.text);
        }
        else {
            this.computedValue = this.computedValue.includes(ev.detail.value) ? [] : [ev.detail.value];
            this.computedText = this.computedText.includes(ev.detail.text) ? [] : [ev.detail.text];
        }
        Array.from(this.el.querySelectorAll('x-select-option'))
            .filter(el => this.computedValue.includes(el.value) || el.selected)
            .forEach((el) => {
            el.selected = this.computedValue.includes(el.value);
        });
        const input = this.el.querySelector('.select-input');
        input.value = '';
        input.dispatchEvent(new InputEvent('input', { bubbles: false }));
        this.setFormValue();
    }
    /**
     * Element event on slot make changes
     */
    handleSlotChange() {
        this.selectOptionByValue(this.value);
    }
    /**
     * Set the actual value to internals
     */
    setFormValue() {
        var _a;
        if (this.multiple) {
            this.value = this.computedValue;
            if (!((_a = this.name) === null || _a === void 0 ? void 0 : _a.length)) {
                return;
            }
            const data = new FormData();
            this.computedValue.forEach((value) => {
                data.append(this.name, value);
            });
            this.internals.setFormValue(data);
        }
        else {
            this.value = this.computedValue[0];
            this.internals.setFormValue(this.computedValue[0]);
        }
    }
    /**
     * This is called on component will load
     */
    componentWillLoad() {
        if (this.isAdvancedSelect()) {
            this.value = Array.from(this.el.querySelectorAll('x-select-option'))
                .filter(el => el.selected)
                .reduce((_, el) => {
                return Array.isArray(_) ? _.push(el.value) && _ : el.value;
            }, this.multiple ? [] : '');
        }
    }
    /**
     * This is called on component did load
     */
    componentDidLoad() {
        setTimeout(() => {
            this.formValidateCallback();
            this.selectOptionByValue(this.value);
        }, 0);
    }
    /**
     * This is called on component did update the element space
     */
    computePositionCustomSelect() {
        if (this.isAdvancedSelect()) {
            const container = this.el.querySelector('.select-items');
            computePosition(this.el, container, {
                placement: 'bottom-start',
                middleware: [size({
                        apply({ availableWidth, availableHeight, elements }) {
                            const items = elements;
                            if (document.documentElement.clientWidth <= 480) {
                                container.style.maxWidth = null;
                            }
                            else {
                                container.style.maxWidth = `${Math.max(200, availableWidth > items.reference.offsetWidth ? items.reference.offsetWidth : availableWidth)}px`;
                            }
                            container.style.maxHeight = `${Math.max(200, availableHeight - 4)}px`;
                        }
                    }), flip(), shift(), offset(4)],
            }).then(({ x, y }) => {
                container.style.left = `${x}px`;
                container.style.top = `${y}px`;
            });
        }
    }
    /**
     * This is called when the 'disabled' attribute of the element or or an ancestor <fieldset> is updated
     *
     * @param disabled
     */
    formDisabledCallback(disabled) {
        this.isDisabled = disabled;
    }
    /**
     * This is called when the parent/owner form is reset
     */
    formResetCallback() {
        this.isValid = true;
        this.internals.setFormValue('');
        const placeholder = this.el.querySelector('[data-placeholder]');
        placeholder === null || placeholder === void 0 ? void 0 : placeholder.setAttribute('selected', 'selected');
    }
    /**
     * This is called when the input is validated
     */
    formValidateCallback(dispatchValidation) {
        var _a, _b;
        if (this.required && isEmpty(this.value)) {
            this.internals.setValidity({ valueMissing: true }, Lang.get('fields.validation.value-missing'));
        }
        else {
            this.internals.setValidity({});
        }
        if (dispatchValidation) {
            this.isValid = this.isAdvancedSelect() ? this.internals.validity.valid : (_b = (_a = this.input) === null || _a === void 0 ? void 0 : _a.validity) === null || _b === void 0 ? void 0 : _b.valid;
            this.onValidateInputEvent.emit(this.isAdvancedSelect() ? this.internals : this.input);
        }
    }
    /**
     * Set element value by event
     *
     * @param event
     */
    onInput(event) {
        var _a;
        this.value = event.target.value;
        (_a = this.internals) === null || _a === void 0 ? void 0 : _a.setFormValue(event.target.value);
    }
    /**
     * This called on input field is unfocused
     */
    onBlurInput() {
        setTimeout(() => {
            var _a;
            this.isFocused = false;
            this.formValidateCallback(true);
            (_a = this.cleanup) === null || _a === void 0 ? void 0 : _a.call(this);
        }, 20);
    }
    /**
     * This called on input field is focused
     */
    onFocusInput() {
        this.isFocused = true;
        if (this.isAdvancedSelect()) {
            this.cleanup = autoUpdate(this.el, this.el.querySelector('.select-items'), this.computePositionCustomSelect.bind(this));
        }
    }
    /**
     * This called on search input have results
     */
    onFilterInput(ev) {
        this.isFiltered = ev.target.value.length > 0;
        setTimeout(() => {
            this.filteredTotal = this.el.querySelectorAll('x-select-option').length;
            this.filteredCount = this.el.querySelectorAll('x-select-option[matched]').length;
        }, 50);
    }
    /**
     * Return validation of showing the input label
     *
     * @returns
     */
    showLabel() {
        var _a, _b;
        return (this.label && this.placeholder) || (this.label && (((_b = (_a = this.value) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : '').length > 0 || this.computedValue.length > 0 || this.isFocused || (this.multiple && !this.isAdvancedSelect())));
    }
    /**
     * Compute the placeholder value
     *
     * @returns
     */
    placeholderValue() {
        if (this.label) {
            if (this.placeholder) {
                return this.placeholder;
            }
            else if (!this.showLabel() || (this.multiple && this.isAdvancedSelect())) {
                return this.label;
            }
        }
        return this.placeholder;
    }
    /**
     * Focus the select input
     */
    focusSelect() {
        var _a;
        const event = new MouseEvent("mousedown", {
            bubbles: true,
            cancelable: true,
            view: window,
        });
        if (this.isAdvancedSelect()) {
            this.isFocused = !this.isFocused;
            setTimeout(() => {
                this.el.querySelector('.select-input').focus();
            }, 20);
        }
        else {
            (_a = this.input) === null || _a === void 0 ? void 0 : _a.dispatchEvent(event);
        }
    }
    /**
     * Select the option element by value
     */
    selectOptionByValue(value) {
        const options = Array.from(this.el.children)
            .filter(el => el.nodeName.toLowerCase() === 'option')
            .map(el => el);
        options && options.length > 0 && options.forEach((option) => {
            if (Array.isArray(value) ? value.includes(option.value) : option.value === value.toString()) {
                option.selected = true;
            }
        });
        if (this.isAdvancedSelect) {
            const advancedOptions = Array.from(this.el.querySelectorAll('x-select-option'));
            this.computedValue = [];
            this.computedText = [];
            advancedOptions === null || advancedOptions === void 0 ? void 0 : advancedOptions.forEach(async (el) => {
                var _a;
                if (Array.isArray(value) ? value.includes(el.value) : value == el.value) {
                    el.selected = true;
                }
                if (el.selected) {
                    this.computedValue.push(el.value);
                    this.computedText.push((_a = el.ariaLabel) !== null && _a !== void 0 ? _a : await el.updateText());
                }
            });
        }
    }
    /**
     * Check if the select use not native options
     */
    isAdvancedSelect() {
        return this.el.querySelector("x-select-option") !== null;
    }
    /**
     * Render component
     */
    render() {
        return h(Host, { key: 'ec3bc01de7ae0d66a7bda468419eeff28021c5a5', "data-for": this.name, style: { maxWidth: this.width } }, h("div", { key: '82dcb149267b601d4c567f164d616cdcbe6a54b8', class: cls("input-container", {
                "focus": this.isFocused,
                "loading": this.loading || this.isLoading,
                "disabled": this.isDisabled,
                "invalid": !this.isValid,
                "required": this.required,
                "multiple": this.multiple,
                "advanced": this.isAdvancedSelect(),
            }) }, h("div", { key: '665dcbc818d6ed2e1619d51fd2f62099ff2175d0', class: "indicator" }, h("slot", { key: 'f15ca0dcd6b9a6d1dad8effd6079ad72bc83966e', name: "indicator" })), h("div", { key: '89026ae0072ac5e6011a789eb00547ef3b670955', class: "separator" }), h("div", { key: '83d1e7c505ac0b09701126583b169213d0b1f63f', class: "wrap" }, this.showLabel() && h("label", { key: 'e31d1cad9b33e6ee624d6fcf4e6d5d2767614b5e', htmlFor: this.inputId }, this.label), this.isAdvancedSelect() ?
            h("div", null, h("input", { id: this.inputId, onFocus: () => this.focusSelect(), style: { width: '0.1px', flex: 'none' }, value: this.computedText.join(', '), required: this.required, disabled: this.isDisabled || this.loading || this.isLoading }), (!this.isFocused || this.multiple) &&
                h("p", { style: { width: this.isFocused ? 'max-content' : '100%' }, onClick: () => this.focusSelect() }, this.computedText.join(', ')), h("input", { tabindex: "-1", id: this.inputId, style: { display: this.isFocused || this.computedValue.length < 1 ? 'block' : 'none' }, class: "select-input", type: "text", autoFocus: this.autofocus, disabled: this.isDisabled || this.loading || this.isLoading, placeholder: this.placeholderValue(), onInput: (ev) => this.onFilterInput(ev), onBlur: () => this.onBlurInput(), onFocus: () => this.onFocusInput() }))
            : h("select", { ref: el => this.input = el, id: this.inputId, required: this.required, disabled: this.isDisabled || this.loading || this.isLoading, autoComplete: this.autocomplete, autoFocus: this.autofocus, multiple: this.multiple, size: this.size, onInput: (e) => this.onInput(e), onBlur: () => this.onBlurInput(), onFocus: () => this.onFocusInput() }, this.placeholder && h("option", { value: "", selected: true, disabled: true, "data-placeholder": true }, this.placeholder), h("slot", null))), h("div", { key: '40d8fd11252725834547de3179d4b469262721e2', class: "field-float-components" }, this.loading && h("div", { key: '29a16d5dfc74f749f7f15ba9a20188ab4fe482e5', class: "loading-indicator" }), h("div", { key: '944424c62446e1d80f560d4d1fc39436841f401f', class: "buttons" }, !(this.multiple && !this.isAdvancedSelect()) && h("x-button", { key: '55181ccc8dbf9961ae290fd9c27471efb6b898a8', tabindex: "-1", class: "dropdown-button", icon: "dropdown", onClick: () => this.focusSelect() }), h("slot", { key: '7e2e9a18207e300e84dd1ec47b21dc728c353e7a', name: "buttons" })), this.info && h("div", { key: '5e4b8c462777b9fee1aacfc7f1044ac484f77375', class: "info" }, h("x-tooltip", { key: '40db2d9eff349bef5a2ac1db10fa6e395c353450', content: this.info }, h("x-icon", { key: 'c27592a50b1d7d509750b8b153f798f6b2948269', name: "info" }))))), this.isAdvancedSelect() && h("div", { key: 'a7b1c8ff5852a7c1558a394500561b309fc111b0', class: cls('select-items', {
                'focused': this.isFocused && !(this.isDisabled || this.loading || this.isLoading),
                'filtered': this.isFiltered,
            }) }, h("slot", { key: 'e5429b6ae63001d21e6e1ed1e6d0fd7dd7f281e5' }), this.isFiltered && h("div", { key: '3acdc172779c2118d15f1e7572555719dfa08c0d', class: "select-results" }, h("span", { key: '89f647d7a713e041bb320ea8a559b6528fc0af06' }, "Mostrando ", h("strong", { key: '6da036e9e065a7e4e684dabe305d52d50b51a09b' }, this.filteredCount), " recomendacion(es) de ", h("strong", { key: '859cd120e63d849e3515456cf97a4670a11e9b5b' }, this.filteredTotal)))));
    }
    static get is() { return "x-select"; }
    static get formAssociated() { return true; }
    static get originalStyleUrls() {
        return {
            "$": ["./style.scss"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["style.css"]
        };
    }
    static get properties() {
        return {
            "label": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Element input label text"
                },
                "attribute": "label",
                "reflect": false
            },
            "name": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Element input name for forms keys"
                },
                "attribute": "name",
                "reflect": false
            },
            "placeholder": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Element input placeholder text"
                },
                "attribute": "placeholder",
                "reflect": false
            },
            "info": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Element input information block"
                },
                "attribute": "info",
                "reflect": false
            },
            "required": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Element input required for forms validations"
                },
                "attribute": "required",
                "reflect": false
            },
            "loading": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Element show loading and block for edit"
                },
                "attribute": "loading",
                "reflect": false
            },
            "autofocus": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Element autofocus on render"
                },
                "attribute": "autofocus",
                "reflect": false
            },
            "multiple": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Element multiple selection"
                },
                "attribute": "multiple",
                "reflect": false
            },
            "size": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Element rows size on multiple selection"
                },
                "attribute": "size",
                "reflect": false
            },
            "width": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Element input width"
                },
                "attribute": "width",
                "reflect": false
            },
            "autocomplete": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "InputAutocompleteTypes",
                    "resolved": "\"name\" | \"on\" | \"off\" | \"tel\" | \"url\" | \"email\" | \"honorific-prefix\" | \"given-name\" | \"additional-name\" | \"family-name\" | \"honorific-suffix\" | \"nickname\" | \"username\" | \"new-password\" | \"current-password\" | \"one-time-code\" | \"organization-title\" | \"organization\" | \"street-address\" | \"address-line1\" | \"address-line2\" | \"address-line3\" | \"address-level4\" | \"address-level3\" | \"address-level2\" | \"address-level1\" | \"country\" | \"country-name\" | \"postal-code\" | \"cc-name\" | \"cc-given-name\" | \"cc-additional-name\" | \"cc-family-name\" | \"cc-number\" | \"cc-exp\" | \"cc-exp-month\" | \"cc-exp-year\" | \"cc-csc\" | \"cc-type\" | \"transaction-currency\" | \"transaction-amount\" | \"language\" | \"bday\" | \"bday-day\" | \"bday-month\" | \"bday-year\" | \"sex\" | \"tel-country-code\" | \"tel-national\" | \"tel-area-code\" | \"tel-local\" | \"tel-extension\" | \"impp\" | \"photo\"",
                    "references": {
                        "InputAutocompleteTypes": {
                            "location": "import",
                            "path": "../x-input/component",
                            "id": "src/components/x-input/component.tsx::InputAutocompleteTypes"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Element input value of the control can be automatically completed by the browser"
                },
                "attribute": "autocomplete",
                "reflect": false,
                "defaultValue": "'off'"
            },
            "value": {
                "type": "string",
                "mutable": true,
                "complexType": {
                    "original": "string | Array<string> | null",
                    "resolved": "string | string[]",
                    "references": {
                        "Array": {
                            "location": "global",
                            "id": "global::Array"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Element input value"
                },
                "attribute": "value",
                "reflect": false,
                "defaultValue": "''"
            }
        };
    }
    static get states() {
        return {
            "isValid": {},
            "isFocused": {},
            "isLoading": {},
            "isDisabled": {},
            "isFiltered": {},
            "computedValue": {},
            "computedText": {},
            "filteredCount": {},
            "filteredTotal": {}
        };
    }
    static get events() {
        return [{
                "method": "onValidateInputEvent",
                "name": "validated",
                "bubbles": false,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "On validate input event"
                },
                "complexType": {
                    "original": "ElementInternals|HTMLSelectElement",
                    "resolved": "ElementInternals | HTMLSelectElement",
                    "references": {
                        "ElementInternals": {
                            "location": "global",
                            "id": "global::ElementInternals"
                        },
                        "HTMLSelectElement": {
                            "location": "global",
                            "id": "global::HTMLSelectElement"
                        }
                    }
                }
            }];
    }
    static get elementRef() { return "el"; }
    static get watchers() {
        return [{
                "propName": "value",
                "methodName": "watchValue"
            }];
    }
    static get listeners() {
        return [{
                "name": "option-selected",
                "method": "handleOptionSelected",
                "target": undefined,
                "capture": false,
                "passive": false
            }, {
                "name": "slotchange",
                "method": "handleSlotChange",
                "target": undefined,
                "capture": false,
                "passive": false
            }];
    }
    static get attachInternalsMemberName() { return "internals"; }
}
