<template>
    <div :class="dropdownClass">
        <div class="dropdown-trigger is-fullwidth">
            <input type="hidden" :name="name"
                :value="selectedValue" />
            <div v-show="!selected" class="control is-expanded">
                <input type="text" :placeholder="placeholder"
                    ref="input" class="input is-fullwidth"
                    @keydown.capture="onKeyPress"
                    @keyup="onKeyUp" @focus="this.cursor < 0 && move(0)"/>
            </div>
            <button v-if="selected" class="button is-normal is-fullwidth has-text-left is-inline-block overflow-hidden"
                    @click="select(-1, false, true)">
                <span class="icon is-small ml-1">
                    <i class="fa fa-pen"></i>
                </span>
                <span class="is-inline-block" v-if="selected">
                    <slot name="button" :index="selectedIndex" :item="selected"
                        :value-field="valueField" :labelField="labelField">
                    {{ selected.data[labelField] }}
                    </slot>
                </span>
            </button>
        </div>
        <div class="dropdown-menu is-fullwidth">
            <div class="dropdown-content" style="overflow: hidden">
                <a v-for="(item, index) in items" :key="item.id"
                    :class="['dropdown-item', (index == this.cursor) ? 'is-active':'']"
                    @click.capture.prevent="select(index, false, false)" :title="item.data[labelField]">
                    <slot name="item" :index="index" :item="item" :value-field="valueField"
                        :labelField="labelField">
                    {{ item.data[labelField] }}
                    </slot>
                </a>
            </div>
        </div>
    </div>
</template>

<script>
// import debounce from 'lodash/debounce'

export default {
    props: {
        url: String,
        model: Function,
        placeholder: String,
        name: String,
        labelField: String,
        valueField: {type: String, default: null},
        count: {type: Number, count: 10},
    },

    data() {
        return {
            value: '',
            items: [],
            selectedIndex: -1,
            cursor: -1,
            isFetching: false,
        }
    },

    computed: {
        selected() {
            let index = this.selectedIndex
            if(index<0)
                return null
            index = Math.min(index, this.items.length-1)
            return this.items[index]
        },
        
        selectedValue() {
            const sel = this.selected
            return sel && (this.valueField ?
                    sel.data[this.valueField] : sel.id)
        },

        selectedLabel() {
            const sel = this.selected
            return sel && sel.data[this.labelField]
        },

        dropdownClass() {
            const active = this.cursor > -1 && this.items.length;
            return ['dropdown', active ? 'is-active':'']
        },
    },

    methods: {
        move(index=-1, relative=false) {
            if(relative)
                index += this.cursor
            this.cursor = Math.max(-1, Math.min(index, this.items.length-1))
        },
    
        select(index=-1, relative=false, active=null) {
            if(relative)
                index += this.selectedIndex
            else if(index == this.selectedIndex)
                return
        
            this.selectedIndex =  Math.max(-1, Math.min(index, this.items.length-1))
            if(index >= 0) {
                this.$refs.input.value = this.selectedLabel
                this.$refs.input.focus()
            }
            if(this.selectedIndex < 0)
                this.$emit('unselect')
            else
                this.$emit('select', index, this.selected, this.selectedValue)

            if(active!==null)
                active && this.move(0) || this.move(-1)
        },

        onKeyPress: function(event) {
            switch(event.keyCode) {
                case 13: this.select(this.cursor, false, false)
                         break
                case 27: this.select()
                         break
                case 38: this.move(-1, true)
                         break
                case 40: this.move(1, true)
                         break
                default: return
            }
            event.preventDefault()
            event.stopPropagation()
        },

        onKeyUp: function(event) {
            const value = event.target.value
            if(value === this.value)
                return

            this.value = value;
            if(!value)
                return this.selected && this.select(-1)

            this.fetch(value)
        },

        fetch: function(query) {
            if(!query || this.isFetching)
                return

            this.isFetching = true
            return this.model.fetch(this.url.replace('${query}', query), {many:true})
                .then(items => { this.items = items || []
                                 this.isFetching = false
                                 this.move(0)
                                 return items },
                      data => {this.isFetching = false; Promise.reject(data)})
        },
    },
}

</script>

