<template>
    <div class="input-group">
        <div class="badge-list form-control form-control-lg" style="position: relative;">
            <span v-for="(option, index) in value" :key="index">
                <slot :option="option" :index="index"></slot>
            </span>
            <input type="text" class="invisible-input" v-model="textinput" ref="input"
                   @keydown="keyDown">
            <ul class="dropdown-menu" style="position: absolute; top: 100%; left: 0; width: 100%; z-index: 100;"
                v-if="filteredOption.length > 0">
                <li v-for="(option, index) in filteredOption" :key="index"
                    @mousedown="chooseOption(option)" @mouseover="selectOption(option)"
                    :class="{chosen: localValue.includes(option), selected: selectedTag === option, 'dropdown-item': true}">
                    {{ option }}
                    <b>
                        <b-icon-check class="checkmark"></b-icon-check>
                        <b-icon-x class="cross"></b-icon-x>
                        <b-icon-plus class="plus"></b-icon-plus>
                    </b>
                </li>
            </ul>
        </div>
    </div>
</template>

<style scoped>
.badge-list {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    padding: 0 .25rem;
}

.badge-list > * {
    flex: 0 1 auto;
    padding: .25rem 0;
}

.badge-list > input.invisible-input {
    flex: 1 1 auto;
}

input.invisible-input {
    border: none;
    outline: none;
    color: #495057;
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right .7rem center;
    background-size: 16px 12px;
}

.invisible-input:focus ~ .dropdown-menu {
    display: block;
}

.dropdown-menu {
    display: none;
    overflow-x: auto;
    max-height: 50vh;
}

.checkmark, .cross, .plus {
    display: none;
}

.dropdown-item.selected {
    background-color: var(--bs-primary);
    color: var(--bs-light);

    & .plus {
        display: inline-block;
    }
}

.dropdown-item.chosen {
    & .checkmark {
        display: inline-block;
    }
}

.dropdown-item.chosen.selected {
    background-color: var(--bs-danger);
    color: var(--bs-light);

    & .cross {
        display: inline-block;
    }

    & .checkmark, & .plus {
        display: none;
    }
}
</style>

<script>
import * as BIcons from "bootstrap-icons-vue";

export default {
    name: "BadgeSelectField",
    data() {
        return {
            textinput: "",
            selectedTag: ""
        }
    },
    components: {
        ...BIcons
    },
    props: {
        value: {
            type: Array,
            required: true
        },
        options: {
            type: Array,
            required: true
        }
    },
    model: {
        prop: "value",
        event: "addElement"
    },
    computed: {
        availableTags() {
            return this.options.filter(option => !this.localValue.includes(option));
        },
        filteredOption() {
            return this.options.filter(option => option.includes(this.textinput) || option === this.selectedTag);
        },
        localValue: {
            get() {
                return this.value;
            },
            set(value) {
            }
        }
    },
    methods: {
        chooseOption(option) {
            this.$emit("addElement", option);
        },
        resetSelection() {
            this.textinput = "";
            this.selectedTag = null;
        },
        selectOption(option) {
            this.selectedTag = option;
        },
        keyDown(event) {
            const key = event.key;
            if (key === "Enter") {
                event.preventDefault();
                this.chooseOption(this.selectedTag);
                this.$refs.input.blur();
            } else if (key === "ArrowDown") {
                event.preventDefault();
                if (this.selectedTag === "") {
                    this.selectedTag = this.filteredOption[0];
                } else {
                    const index = this.filteredOption.indexOf(this.selectedTag);
                    if (index < this.filteredOption.length - 1) {
                        this.selectedTag = this.filteredOption[index + 1];
                    } else {
                        this.selectedTag = this.filteredOption[0];
                    }
                    setTimeout(() => {
                        const element = this.$el.querySelector(".selected");
                        if (element) {
                            element.scrollIntoView({block: "nearest"});
                        }
                    }, 0);
                }
            } else if (key === "ArrowUp") {
                event.preventDefault();
                if (this.selectedTag === "") {
                    this.selectedTag = this.filteredOption[this.filteredOption.length - 1];
                } else {
                    const index = this.filteredOption.indexOf(this.selectedTag);
                    if (index > 0) {
                        this.selectedTag = this.filteredOption[index - 1];
                    } else {
                        this.selectedTag = this.filteredOption[this.filteredOption.length - 1];
                    }
                    setTimeout(() => {
                        const element = this.$el.querySelector(".selected");
                        if (element) {
                            element.scrollIntoView({block: "nearest"});
                        }
                    }, 0);
                }
            } else if (key === "ArrowRight") {
                if (event.target.selectionStart === this.textinput.length) {
                    event.preventDefault();
                    this.chooseOption(this.selectedTag);
                }
            } else if (key === "Escape") {
                event.preventDefault();
                this.$refs.input.blur();
            }
        }
    }
}
</script>