<script setup>
import { ref, toRefs, computed, watch, onMounted } from 'vue';
import { useI18n } from 'vue-i18n';
const emit = defineEmits(['update:modelValue', 'update:options']);

const $props = defineProps({
    modelValue: {
        type: [String, Number, Object],
        default: null
    },
    options: {
        type: Array,
        default: () => []
    },
    optionLabel: {
        type: [String],
        default: 'name'
    },
    optionValue: {
        type: String,
        default: 'id'
    },
    optionFilter: {
        type: String,
        default: null
    },
    dataQuery: {
        type: String,
        default: ''
    },
    filterOptions: {
        type: [Array],
        default: () => []
    },
    isClearable: {
        type: Boolean,
        default: true
    },
    defaultFilter: {
        type: Boolean,
        default: true
    },
    fields: {
        type: Array,
        default: null
    },
    where: {
        type: Object,
        default: null
    },
    sortBy: {
        type: String,
        default: null
    },
    limit: {
        type: [Number, String],
        default: '30'
    },
    focusOnMount: {
        type: Boolean,
        default: false
    },
    useLike: {
        type: Boolean,
        default: true
    }
});

const { t } = useI18n();
const requiredFieldRule = val => val ?? t('fieldRequired');

const { optionLabel, optionValue, options } = toRefs($props);
const myOptions = ref([]);
const myOptionsOriginal = ref([]);
const vnSelectRef = ref();
const lastVal = ref();

const value = computed({
    get() {
        return $props.modelValue;
    },
    set(value) {
        emit('update:modelValue', value);
    }
});

watch(options, newValue => {
    setOptions(newValue);
});

onMounted(() => {
    setOptions(options.value);
    if ($props.focusOnMount) {
        setTimeout(() => vnSelectRef.value.showPopup(), 300);
    }
});

function setOptions(data) {
    myOptions.value = JSON.parse(JSON.stringify(data));
    myOptionsOriginal.value = JSON.parse(JSON.stringify(data));
}

function filter(val, options) {
    const search = val.toString().toLowerCase();

    if (!search) return options;

    return options.filter(row => {
        if ($props.filterOptions.length) {
            return $props.filterOptions.some(prop => {
                const propValue = String(row[prop]).toLowerCase();
                return propValue.includes(search);
            });
        }

        const id = row.id;
        const optionLabel = String(row[$props.optionLabel]).toLowerCase();

        return id === search || optionLabel.includes(search);
    });
}

async function filterHandler(val, update) {
    if (!val && lastVal.value === val) {
        lastVal.value = val;
        return update();
    }
    lastVal.value = val;

    if (!$props.defaultFilter) return update();
    const newOptions = filter(val, myOptionsOriginal.value);

    setTimeout(() => {
        update(
            () => {
                myOptions.value = newOptions;
            },
            ref => {
                if (val !== '' && ref.options.length > 0) {
                    ref.setOptionIndex(-1);
                    ref.moveOptionSelection(1, true);
                }
            }
        );
    }, 300);
}
</script>

<template>
    <QSelect
        v-model="value"
        :options="myOptions"
        :option-label="optionLabel"
        :option-value="optionValue"
        v-bind="$attrs"
        emit-value
        map-options
        use-input
        @filter="filterHandler"
        hide-selected
        fill-input
        ref="vnSelectRef"
        lazy-rules
        :class="{ required: $attrs.required }"
        :rules="$attrs.required ? [requiredFieldRule] : null"
        virtual-scroll-slice-size="options.length"
    >
        <template v-if="isClearable" #append>
            <QIcon
                v-show="value"
                name="close"
                @click.stop="value = null"
                class="cursor-pointer"
                size="xs"
            />
        </template>
        <template
            v-for="(_, slotName) in $slots"
            #[slotName]="slotData"
            :key="slotName"
        >
            <slot :name="slotName" v-bind="slotData ?? {}" :key="slotName" />
        </template>
        <template #no-option>
            <QItem>
                <QItemSection class="text-grey">
                    {{ t('emptyList') }}
                </QItemSection>
            </QItem>
        </template>
    </QSelect>
</template>

<style scoped lang="scss">
.q-field--outlined {
    max-width: 100%;
}
</style>
