import { library } from '@fortawesome/fontawesome-svg-core';
import { faAngleDown } from '@fortawesome/free-solid-svg-icons';
import { createPopper } from '@popperjs/core';
import { h } from "@stencil/core";
import { getInputCreator } from '../bce-input-creator/input-creator';
library.add(faAngleDown);
export class Select {
    constructor() {
        this.type = 'checkbox';
        this._open = false;
        this._initialized = false;
        this._initialValue = this.value;
        this._inputCreator = getInputCreator(this, err => (this.error = !!err));
        this._options = [];
        this.handleBlur = async () => {
            this.hasFocus = false;
            await new Promise(res => setTimeout(res, 200));
            this._open = this._options.some(o => o.hasFocus);
        };
        this.handleClick = () => {
            switch (this.type) {
                case 'checkbox':
                case 'filter':
                    this.value = this._options
                        .filter(option => !!option.value && !!option.checked)
                        .map(option => option.value);
                    return;
                case 'choice':
                case 'radio':
                    const option = this._options.find(option => option.checked);
                    this.value = option ? option.value : null;
                    return;
            }
        };
        this.handleDropdownClick = () => {
            // this._open = !this._open;
        };
        this.handleFilter = (event) => {
            var _a;
            const value = event.target.value || '';
            const filter = value.toLowerCase().trim();
            for (const option of this._options) {
                const check1 = option.innerText.toLowerCase();
                const check2 = (_a = option.value) === null || _a === void 0 ? void 0 : _a.toLowerCase();
                const visible = check1.indexOf(filter) >= 0 ||
                    (check2 ? check2.indexOf(filter) >= 0 : false);
                option.style.display = visible ? '' : 'none';
            }
            event.stopPropagation();
        };
        this.handleFocus = () => {
            this.hasFocus = true;
            this._open = true;
        };
        this.handleSlotChange = () => {
            // Remove existing event listeners
            for (const option of this._options)
                this.removeEventHandlers(option);
            // Load new options
            const children = Array.from(this.el.childNodes);
            this._options = children.filter(n => ['BCE-CHIP', 'BCE-OPTION'].indexOf(n.nodeName) >= 0);
            // Initialize options & attach event listeners
            for (const option of this._options) {
                option.type = this.type;
                option.name = this.name;
                this.attachEventHandlers(option);
            }
        };
    }
    watchValue(value) {
        if (this._initialized)
            this._inputCreator.handleInput();
        switch (this.type) {
            case 'checkbox':
            case 'filter':
                const values = Array.isArray(value)
                    ? value
                    : (value && value.split(',').map(v => v.trim())) || [];
                for (const option of this._options)
                    option.checked = values.indexOf(option.value || '') >= 0;
                return;
            case 'choice':
            case 'radio':
                for (const option of this._options)
                    option.checked = this.value === option.value;
                return;
        }
    }
    handleChip(event) {
        const dispatch = !equal(this.value || null, event.detail || null);
        this.value = event.detail;
        if (this.type === 'dropdown') {
            this.updateDropdown();
            this._open = false;
        }
        if (dispatch) {
            const e = new Event('input', { bubbles: true, cancelable: true });
            this.el.dispatchEvent(e);
        }
    }
    async reset() {
        this.value = this._initialValue;
        this._inputCreator.reset();
    }
    async validate(silent = false) {
        return this._inputCreator.validate(silent);
    }
    attachEventHandlers(el) {
        el.addEventListener('blur', this.handleBlur);
        el.addEventListener('click', this.handleClick);
        el.addEventListener('focus', this.handleFocus);
    }
    removeEventHandlers(el) {
        el.removeEventListener('blur', this.handleBlur);
        el.removeEventListener('click', this.handleClick);
        el.removeEventListener('focus', this.handleFocus);
    }
    updateDropdown() {
        const option = this._options.find(o => o.value === this.value);
        const input = this.el.shadowRoot.querySelector('bce-input');
        input.value = (option === null || option === void 0 ? void 0 : option.innerText) || '';
    }
    componentDidLoad() {
        const slot = this.el.shadowRoot.querySelector('slot');
        if (slot) {
            slot.addEventListener('slotchange', this.handleSlotChange);
            this.handleSlotChange();
        }
        this.watchValue(this.value);
        if (this.type === 'dropdown') {
            const root = this.el.shadowRoot;
            const ref = '.trigger bce-input';
            const reference = root.querySelector(ref);
            const dropdown = root.querySelector('.dropdown');
            // Create popper.js dropdown
            createPopper(reference, dropdown, {
                strategy: 'fixed',
                placement: 'bottom-start',
                modifiers: [{ name: 'offset', options: { offset: [0, 2] } }]
            });
            // Patch popper.js fixed position
            new window.ResizeObserver(() => {
                const { x, width } = reference.getBoundingClientRect();
                const match = dropdown.style.transform.match(/^translate3d\((\d+)px/);
                const offset = match ? parseFloat(match[1]) : 0;
                dropdown.style.left = `${x - offset}px`;
                dropdown.style.width = width + 'px';
            }).observe(reference);
            this.updateDropdown();
        }
        this._initialized = true;
    }
    renderDropdown() {
        const InputCreator = this._inputCreator;
        return (h(InputCreator, null,
            h("div", { class: "trigger" },
                h("bce-input", { "data-active": this._open, onBlur: this.handleBlur, onClick: this.handleDropdownClick, onFocus: this.handleFocus, onInput: this.handleFilter }),
                h("bce-icon", { pre: "fas", name: "angle-down", "fixed-width": true })),
            h("div", { class: "dropdown", "aria-expanded": this._open, "data-active": this._open },
                h("slot", null))));
    }
    renderFieldset() {
        const InputCreator = this._inputCreator;
        return (h(InputCreator, null,
            h("fieldset", null,
                this.label && h("legend", null, this.label),
                h("slot", null))));
    }
    render() {
        if (this.type === 'input')
            console.warn('[bce-select] The input type is unimplemented.');
        switch (this.type) {
            case 'action':
            case 'checkbox':
            case 'choice':
            case 'filter':
            case 'input':
            case 'radio':
                return this.renderFieldset();
            case 'dropdown':
                return this.renderDropdown();
        }
    }
    static get is() { return "bce-select"; }
    static get encapsulation() { return "shadow"; }
    static get originalStyleUrls() { return {
        "$": ["bce-select.scss"]
    }; }
    static get styleUrls() { return {
        "$": ["bce-select.css"]
    }; }
    static get properties() { return {
        "center": {
            "type": "boolean",
            "mutable": false,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "center",
            "reflect": true
        },
        "error": {
            "type": "boolean",
            "mutable": false,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "error",
            "reflect": true
        },
        "hasFocus": {
            "type": "boolean",
            "mutable": false,
            "complexType": {
                "original": "boolean",
                "resolved": "boolean",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "focus",
            "reflect": true
        },
        "info": {
            "type": "string",
            "mutable": false,
            "complexType": {
                "original": "string",
                "resolved": "string",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "info",
            "reflect": true
        },
        "label": {
            "type": "string",
            "mutable": false,
            "complexType": {
                "original": "string",
                "resolved": "string",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "label",
            "reflect": true
        },
        "name": {
            "type": "string",
            "mutable": false,
            "complexType": {
                "original": "string",
                "resolved": "string",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "name",
            "reflect": true
        },
        "tooltip": {
            "type": "string",
            "mutable": false,
            "complexType": {
                "original": "string",
                "resolved": "string",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "tooltip",
            "reflect": false
        },
        "type": {
            "type": "string",
            "mutable": false,
            "complexType": {
                "original": "SelectType",
                "resolved": "\"action\" | \"checkbox\" | \"choice\" | \"dropdown\" | \"filter\" | \"input\" | \"radio\"",
                "references": {
                    "SelectType": {
                        "location": "import",
                        "path": "../../models/select-type"
                    }
                }
            },
            "required": false,
            "optional": false,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "type",
            "reflect": true,
            "defaultValue": "'checkbox'"
        },
        "validation": {
            "type": "string",
            "mutable": false,
            "complexType": {
                "original": "string",
                "resolved": "string",
                "references": {}
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "validation",
            "reflect": true
        },
        "value": {
            "type": "string",
            "mutable": true,
            "complexType": {
                "original": "SelectValue",
                "resolved": "string | string[]",
                "references": {
                    "SelectValue": {
                        "location": "import",
                        "path": "../../models/select-value"
                    }
                }
            },
            "required": false,
            "optional": true,
            "docs": {
                "tags": [],
                "text": ""
            },
            "attribute": "value",
            "reflect": false
        }
    }; }
    static get states() { return {
        "_open": {}
    }; }
    static get methods() { return {
        "reset": {
            "complexType": {
                "signature": "() => Promise<void>",
                "parameters": [],
                "references": {
                    "Promise": {
                        "location": "global"
                    }
                },
                "return": "Promise<void>"
            },
            "docs": {
                "text": "",
                "tags": []
            }
        },
        "validate": {
            "complexType": {
                "signature": "(silent?: boolean) => Promise<ValidatorError[]>",
                "parameters": [{
                        "tags": [],
                        "text": ""
                    }],
                "references": {
                    "Promise": {
                        "location": "global"
                    },
                    "ValidatorError": {
                        "location": "import",
                        "path": "../../utils/validator"
                    }
                },
                "return": "Promise<ValidatorError[]>"
            },
            "docs": {
                "text": "",
                "tags": []
            }
        }
    }; }
    static get elementRef() { return "el"; }
    static get watchers() { return [{
            "propName": "value",
            "methodName": "watchValue"
        }]; }
    static get listeners() { return [{
            "name": "bce-core:chip",
            "method": "handleChip",
            "target": undefined,
            "capture": false,
            "passive": false
        }, {
            "name": "bce-core:option",
            "method": "handleChip",
            "target": undefined,
            "capture": false,
            "passive": false
        }]; }
}
const equal = (a, b) => {
    if (typeof a !== typeof b)
        return false;
    if (!Array.isArray(a) || !Array.isArray(b))
        return a === b;
    if (a.length != b.length)
        return false;
    for (let i = 0; i < a.length; i++)
        if (a[i] !== b[i])
            return false;
    return true;
};
