import { h } from "@stencil/core";
import debounce from "lodash/debounce";
import { buildClassList, hasValueChanged } from "@boldpenguin/sdk-utility";
const keyboardNavigation = {
    next: ['ArrowDown'],
    previous: ['ArrowUp'],
    select: ['Enter'],
};
export class BpSdkAutocompleteInput {
    constructor() {
        this.hideChoices = () => {
            this._showChoices = false;
        };
        this.onFocus = () => {
            this.isFocused = true;
        };
        this.onBlur = () => {
            if (!this.disableDropdown) {
                this.el.querySelector('input').value = this.getText(this.choice);
            }
            this.isFocused = false;
        };
        this.debounceFilterChoices = debounce(this.filterChoices, 300);
        this.choiceSelected = (choice) => {
            var _a;
            this._showChoices = false;
            if (choice) {
                this.choice = choice;
                this.value = choice.id;
            }
            else if (this.allowFallthrough) {
                this.value = this.filterText;
            }
            (_a = this.el.querySelector('.bp-sdk-autocomplete__input')) === null || _a === void 0 ? void 0 : _a.focus();
            this.removeActiveAnswer.emit();
        };
        this.onKeydown = (event) => {
            const key = event.key;
            if (event.metaKey || event.altKey) {
                return;
            }
            switch (key) {
                case 'ArrowUp':
                case 'ArrowDown':
                case 'Enter':
                    event.preventDefault();
                    this.handleKeyEvent(key);
                    break;
                case 'Tab':
                case 'Escape':
                    this._showChoices = false;
                    break;
                case 'Meta':
                case 'Control':
                case 'Alt':
                    break;
                default:
                    this.debounceFilterChoices();
                    break;
            }
        };
        this.onOptionClick = (choice) => (e) => {
            e.preventDefault();
            this.choiceSelected(choice);
        };
        this.answerId = undefined;
        this.questionId = undefined;
        this.fieldType = undefined;
        this.choiceId = undefined;
        this.choices = [];
        this.code = undefined;
        this.placeholder = '';
        this.required = false;
        this.errors = undefined;
        this.errorText = undefined;
        this.labelId = undefined;
        this.showChoices = false;
        this.touched = false;
        this.pristine = true;
        this.isCompleted = false;
        this.isReadOnly = false;
        this.label = undefined;
        this.labelledBy = undefined;
        this.disableDropdown = false;
        this.allowFallthrough = false;
        this.showNoChoicesFallback = true;
        this.helpText = undefined;
        this.answeredBySource = undefined;
        this._choices = [];
        this._labelledBy = undefined;
        this._showChoices = false;
        this.filterText = '';
        this.value = undefined;
        this.choice = undefined;
        this.choiceText = '';
        this.focusedIndex = 0;
        this.useExternal = false;
        this.isFocused = false;
        this.text = '';
    }
    resetState() {
        this._showChoices = false;
        this.focusedIndex = 0;
        this.isFocused = false;
    }
    connectedCallback() {
        this.resetState();
    }
    componentWillLoad() {
        this.useExternal = !!customElements.get('bp-sdk-external-autocomplete-input');
        customElements.whenDefined('bp-sdk-external-autocomplete-input').then(() => {
            this.useExternal = true;
        });
        this.onChoicesChange(this.choices);
        this.onChoiceIdChange(this.choiceId);
        this.onShowChoicesChange(this.showChoices);
        this.onChoiceChange(this.choice);
        this.onAriaLabelledByChange(this.labelId);
        this.onLabelledByChange(this.labelledBy);
        this.checkForSelectedChoice();
    }
    onAriaLabelledByChange(labelId) {
        this.updateLabelledBy(labelId, this.labelledBy);
    }
    onLabelledByChange(labelledBy) {
        this.updateLabelledBy(this.labelId, labelledBy);
    }
    updateLabelledBy(aria, ids) {
        const prefix = ids ? `${ids} ` : '';
        this._labelledBy = `${prefix}${aria !== null && aria !== void 0 ? aria : ''}` || undefined;
    }
    onChoicesChange(choices) {
        if (JSON.stringify(choices) !== JSON.stringify(this._choices)) {
            this._choices = choices;
        }
        this.onChoiceIdChange(this.choiceId);
    }
    onChoiceIdChange(choiceId) {
        this.choice = this._choices.find((choice) => choice.id === choiceId);
    }
    onShowChoicesChange(newValue) {
        this._showChoices = this.isFocused && newValue;
    }
    getText(choice) {
        return choice ? this.displayChoice(choice) : '';
    }
    onChoiceChange(choice) {
        this.choiceText = this.getText(choice);
    }
    onChoiceTextChange(text) {
        this.text = text;
    }
    onValueChange(newValue, oldValue) {
        this._showChoices = false;
        if (newValue !== this.choiceId && hasValueChanged(newValue, oldValue)) {
            this.valueUpdate.emit([newValue]);
        }
    }
    filterChoices() {
        const input = this.el.querySelector('input');
        this.text = this.filterText = input.value;
        this._showChoices = this.isFocused && !!this.filterText;
    }
    onFilterChange(value) {
        this._showChoices = this.isFocused;
        this.updateActiveAnswer.emit(this.answerId);
        this.filterUpdate.emit({
            id: this.questionId,
            value,
        });
    }
    checkForSelectedChoice() {
        if (this.choiceId) {
            this._choices.map((choice) => {
                if (this.choiceId === choice.id) {
                    this.value = choice.id;
                    this.choice = choice;
                }
            });
        }
    }
    displayChoice(choice) {
        return choice === null || choice === void 0 ? void 0 : choice.value;
    }
    handleKeyEvent(keyName) {
        const options = this.getKeyEventOptions(keyName);
        const indexToSelect = this.getIndexToSelect(keyName, options);
        this.mapKeyEventToAction(indexToSelect, options);
    }
    getKeyEventOptions(keyName) {
        const goToNext = keyboardNavigation.next.includes(keyName);
        const goToPrevious = keyboardNavigation.previous.includes(keyName);
        const isOpenOrSelectKey = keyboardNavigation.select.includes(keyName);
        return {
            goToNext,
            goToPrevious,
            shouldMoveIndex: this._showChoices && (goToPrevious || goToNext),
            isOpenOrSelectKey,
        };
    }
    getIndexToSelect(keyName, { goToPrevious, shouldMoveIndex, isOpenOrSelectKey }) {
        let indexToSelect;
        if (isOpenOrSelectKey && this._showChoices) {
            indexToSelect = this.focusedIndex;
        }
        else if (keyName === 'Escape') {
            this._showChoices = false;
        }
        else if (shouldMoveIndex && !this._showChoices) {
            indexToSelect = this.focusedIndex == null ? 0 : this.focusedIndex + (goToPrevious ? -1 : 1);
        }
        return indexToSelect;
    }
    mapKeyEventToAction(indexToSelect, { shouldMoveIndex, goToPrevious, goToNext, }) {
        if (typeof indexToSelect === 'number') {
            this.selectOptionByIndex(indexToSelect);
        }
        else if (shouldMoveIndex && this._showChoices) {
            this.focusOption(this.focusedIndex + (goToPrevious ? -1 : 1));
        }
        else if (goToNext || goToPrevious) {
            this.filterText = this.displayChoice(this.choice);
            this.focusOption(0);
        }
    }
    focusOption(index) {
        this._showChoices = this.isFocused;
        this.focusedIndex = this.getSelectableIndex(index);
    }
    selectOptionByIndex(index) {
        const selectableIndex = this.getSelectableIndex(index);
        this.focusedIndex = selectableIndex;
        const choice = this._choices[this.focusedIndex];
        this.choiceSelected(choice);
    }
    getSelectableIndex(index) {
        const lastIndex = this._choices.length - 1;
        const selectableIndex = index <= 0 ? 0 : index > lastIndex ? lastIndex : index;
        return selectableIndex;
    }
    handleOutsideClick() {
        this.hideChoices();
    }
    handleClick(e) {
        if (this.useExternal) {
            return;
        }
        e.stopPropagation();
    }
    render() {
        return [this.useExternal && this.renderExternal(), !this.useExternal && this.renderInternal()];
    }
    renderExternal() {
        return (h("bp-sdk-external-autocomplete-input", { allowFallthrough: this.allowFallthrough, answerId: this.answerId, choiceId: this.choiceId, choices: this._choices, code: this.code, disableDropdown: this.disableDropdown, errorText: this.errorText, errors: this.errors, fieldType: this.fieldType, helpText: this.helpText, answeredBySource: this.answeredBySource, isCompleted: this.isCompleted, isReadOnly: this.isReadOnly, labelId: this.labelId, label: this.label, labelledBy: this.labelledBy, placeholder: this.placeholder, pristine: this.pristine, questionId: this.questionId, required: this.required, showChoices: this.showChoices, showNoChoicesFallback: this.showNoChoicesFallback, touched: this.touched }));
    }
    renderInternal() {
        var _a;
        let input;
        if (this.isReadOnly) {
            input = this.renderReadOnlyElement(this.text);
        }
        else {
            input = [
                h("input", { id: `bp-sdk-autocomplete__${this.answerId}`, class: "bp-sdk-autocomplete__input", "aria-controls": `bp-sdk-autocomplete__${this.answerId}-listbox`, "aria-autocomplete": "list", placeholder: this.placeholder, "aria-labelledby": this._labelledBy, type: "text", value: this.text, onBlur: this.onBlur, onFocus: this.onFocus, onKeyDown: this.onKeydown }),
                this.renderOptions(),
            ];
        }
        return (h("div", { class: "bp-sdk-autocomplete__container", "aria-expanded": this._showChoices, "aria-owns": `bp-sdk-autocomplete__${this.answerId}-listbox`, "aria-haspopup": "listbox", onBlur: this.hideChoices }, h("label", { id: this.labelId, htmlFor: `bp-sdk-autocomplete__${this.answerId}`, class: "bp-sdk-label bp-sdk-autocomplete__label", innerHTML: this.label }), input, this.touched && !this.pristine && ((this.errorText && !this.isCompleted) || !!((_a = this.errors) === null || _a === void 0 ? void 0 : _a.length)) && (h("bp-sdk-errors-container", { answerId: this.answerId, questionId: this.questionId, fieldType: this.fieldType, errors: this.errors, errorText: this.errorText }))));
    }
    renderOptions() {
        var _a;
        if (this.disableDropdown) {
            return;
        }
        else if ((_a = this._choices) === null || _a === void 0 ? void 0 : _a.length) {
            return (h("ul", { class: buildClassList('bp-sdk-autocomplete__list', {
                    'bp-sdk-visually-hidden': !this._showChoices,
                }), id: `bp-sdk-autocomplete__${this.answerId}-listbox`, role: "listbox", "aria-labelledby": this.labelId, tabindex: "-1" }, this._choices.map((choice, i) => (h("li", { onClick: this.onOptionClick(choice), "aria-labelledby": this.labelId, class: buildClassList(`bp-sdk-autocomplete__list-item bp-sdk-autocomplete__item-${choice.id}`, {
                    'bp-sdk-autocomplete__list-item--selected': this.choiceId === choice.id,
                }), role: "option", "aria-selected": (this.focusedIndex == i).toString(), tabindex: "1" }, h("span", { class: `bp-sdk-autocomplete__list-item-text bp-sdk-autocomplete__list-item-text-${choice.id}` }, this.displayChoice(choice)))))));
        }
        else if (this.showNoChoicesFallback) {
            return (h("div", { class: buildClassList('bp-sdk-no-results', {
                    'bp-sdk-visually-hidden': !this._showChoices,
                }) }, h("span", null, "No Results")));
        }
    }
    renderReadOnlyElement(value) {
        return h("span", { class: "read-only-value" }, value);
    }
    static get is() { return "bp-sdk-autocomplete-input"; }
    static get originalStyleUrls() {
        return {
            "$": ["bp-sdk-autocomplete-input.css"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["bp-sdk-autocomplete-input.css"]
        };
    }
    static get properties() {
        return {
            "answerId": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Answer id"
                },
                "attribute": "answer-id",
                "reflect": false
            },
            "questionId": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Question id"
                },
                "attribute": "question_id",
                "reflect": false
            },
            "fieldType": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Field type"
                },
                "attribute": "field_type",
                "reflect": false
            },
            "choiceId": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "*\nSelected choice id"
                },
                "attribute": "choice_id",
                "reflect": false
            },
            "choices": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "IChoice[]",
                    "resolved": "IChoice[]",
                    "references": {
                        "IChoice": {
                            "location": "import",
                            "path": "@boldpenguin/sdk-types",
                            "id": "../sdk-types/dist/types.d.ts::IChoice"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "*\nChoices to display"
                },
                "defaultValue": "[]"
            },
            "code": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "question code"
                },
                "attribute": "code",
                "reflect": false
            },
            "placeholder": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Placeholder to display"
                },
                "attribute": "placeholder",
                "reflect": false,
                "defaultValue": "''"
            },
            "required": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Is required"
                },
                "attribute": "required",
                "reflect": false,
                "defaultValue": "false"
            },
            "errors": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "string[] | undefined",
                    "resolved": "string[]",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Error messages"
                }
            },
            "errorText": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string | undefined",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Error text"
                },
                "attribute": "error_text",
                "reflect": false
            },
            "labelId": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Aria label id's that describes input for screen readers"
                },
                "attribute": "label-id",
                "reflect": false
            },
            "showChoices": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Show choices"
                },
                "attribute": "show_choices",
                "reflect": false,
                "defaultValue": "false"
            },
            "touched": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Is touched"
                },
                "attribute": "touched",
                "reflect": false,
                "defaultValue": "false"
            },
            "pristine": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Is pristine"
                },
                "attribute": "pristine",
                "reflect": false,
                "defaultValue": "true"
            },
            "isCompleted": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Is answer in complete state"
                },
                "attribute": "is_completed",
                "reflect": false,
                "defaultValue": "false"
            },
            "isReadOnly": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "When true, the field will be readonly. It will display only the label and value as plain text."
                },
                "attribute": "is-read-only",
                "reflect": false,
                "defaultValue": "false"
            },
            "label": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Label to use"
                },
                "attribute": "label",
                "reflect": false
            },
            "labelledBy": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Labels that describe group"
                },
                "attribute": "labelled-by",
                "reflect": false
            },
            "disableDropdown": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Disables dropdown"
                },
                "attribute": "disable-dropdown",
                "reflect": false,
                "defaultValue": "false"
            },
            "allowFallthrough": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Allow text to fall through if no selected choices"
                },
                "attribute": "allow-fallthrough",
                "reflect": false,
                "defaultValue": "false"
            },
            "showNoChoicesFallback": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Should show no choices fallback if list is empty"
                },
                "attribute": "show-no-choices-fallback",
                "reflect": false,
                "defaultValue": "true"
            },
            "helpText": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Help text"
                },
                "attribute": "help-text",
                "reflect": false
            },
            "answeredBySource": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string | undefined",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Specifically how the question was answered (ie. \"ACORD 126\")"
                },
                "attribute": "answered-by-source",
                "reflect": false
            }
        };
    }
    static get states() {
        return {
            "_choices": {},
            "_labelledBy": {},
            "_showChoices": {},
            "filterText": {},
            "value": {},
            "choice": {},
            "choiceText": {},
            "focusedIndex": {},
            "useExternal": {},
            "isFocused": {},
            "text": {}
        };
    }
    static get events() {
        return [{
                "method": "valueUpdate",
                "name": "valueUpdate",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "complexType": {
                    "original": "string[]",
                    "resolved": "string[]",
                    "references": {}
                }
            }, {
                "method": "filterUpdate",
                "name": "filterUpdate",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "complexType": {
                    "original": "{ id: string; value: string }",
                    "resolved": "{ id: string; value: string; }",
                    "references": {}
                }
            }, {
                "method": "removeActiveAnswer",
                "name": "removeActiveAnswer",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "complexType": {
                    "original": "void",
                    "resolved": "void",
                    "references": {}
                }
            }, {
                "method": "updateActiveAnswer",
                "name": "updateActiveAnswer",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                }
            }];
    }
    static get elementRef() { return "el"; }
    static get watchers() {
        return [{
                "propName": "labelId",
                "methodName": "onAriaLabelledByChange"
            }, {
                "propName": "labelledBy",
                "methodName": "onLabelledByChange"
            }, {
                "propName": "choices",
                "methodName": "onChoicesChange"
            }, {
                "propName": "choiceId",
                "methodName": "onChoiceIdChange"
            }, {
                "propName": "showChoices",
                "methodName": "onShowChoicesChange"
            }, {
                "propName": "choice",
                "methodName": "onChoiceChange"
            }, {
                "propName": "choiceText",
                "methodName": "onChoiceTextChange"
            }, {
                "propName": "value",
                "methodName": "onValueChange"
            }, {
                "propName": "filterText",
                "methodName": "onFilterChange"
            }];
    }
    static get listeners() {
        return [{
                "name": "click",
                "method": "handleOutsideClick",
                "target": "document",
                "capture": false,
                "passive": false
            }, {
                "name": "click",
                "method": "handleClick",
                "target": undefined,
                "capture": false,
                "passive": false
            }];
    }
}
