<template>
    <select
        :value="localValue"
        @change="handleChange"
        :multiple="multiple"
        :disabled="disabled"
        :data-placeholder="placeholder"
    >
        <option value="" v-if="placeholder && !multiple" :disabled="!allowDeselect && localValue !== ''">{{ placeholder }}</option>
        <option
            v-for="option in localOptions"
            :key="option[trackBy]"
            :value="option[trackBy]"
            :selected="isSelected(option)"
        >
            {{ option[label] }}
        </option>
    </select>
</template>

<script>
    export default {
        name: 'select-field',
        props: {
            value: {
                type: [String, Number, Array, Object, Boolean],
                default: null
            },
            options: {
                type: [Array, Object],
                default: () => []
            },
            label: {
                type: String,
                default: 'label'
            },
            trackBy: {
                type: String,
                default: 'id'
            },
            multiple: {
                type: Boolean,
                default: false
            },
            placeholder: {
                type: String,
                default: 'Select'
            },
            allowEmpty: {
                type: Boolean,
                default: false
            },
            allowAll: {
                type: Boolean,
                default: false
            },
            disabled: {
                type: Boolean,
                default: false
            },
            allowDeselect: {
                type: Boolean,
                default: false
            },
            onValueReturn: {
                type: Object,
                default: () => ({})
            },
        },
        methods: {
            handleChange(event) {
                let value = event.target.value;

                // Handle onValueReturn custom mapping
                if (typeof this.onValueReturn[value] !== 'undefined') {
                    return this.$emit('input', this.onValueReturn[value]);
                }

                // Handle allowAll (-1 returns null)
                if (this.allowAll && (value === '-1' || value === -1)) {
                    return this.$emit('input', null);
                }

                // Handle multiple select
                if (this.multiple) {
                    const selected = Array.from(event.target.selectedOptions).map(opt => opt.value);
                    return this.$emit('input', selected);
                }

                this.$emit('input', value);
            },
            isSelected(option) {
                if (this.multiple) {
                    return Array.isArray(this.value) && this.value.includes(option[this.trackBy]);
                }

                return option[this.trackBy] === this.localValue;
            }
        },
        computed: {
            localOptions() {
                let vm = this,
                    options = [];

                if (this.allowAll) {
                    options.push({
                        [this.trackBy]: -1,
                        [this.label]: 'All'
                    })
                }

                if (Array.isArray(this.options)) {
                    // Array of plain strings -> map each to a {trackBy, label} pair.
                    // Array of objects -> use as-is (appended after any allowAll sentinel).
                    if (this.options.some((key) => typeof key === 'string')) {
                        vm.options.forEach((key) => {
                            if(typeof key == 'string') {
                                if(key.length) {
                                    options.push({
                                        [vm.trackBy]: key,
                                        [vm.label]: key
                                    })
                                }
                            }
                        });
                    } else {
                        options = options.concat(this.options)
                    }
                } else {
                    Object.keys(this.options).forEach(function (key) {
                        options.push({
                            [vm.trackBy]: key,
                            [vm.label]: vm.options[key]
                        })
                    });
                }

                return this.allowEmpty
                    ? [{[this.trackBy]: '', [this.label]: ''}].concat(options)
                    : options
            },
            localValue() {
                return this.allowAll && this.value === null ? -1 : this.value;
            }
        }
    }
</script>
