<script lang="ts" setup generic="T extends Record<string, unknown>">
import { onMounted, ref, watch } from 'vue';
import { selectFilterOptionRefMod } from 'src/stores/utils';
import { QSelect } from 'quasar';

const model = defineModel<string | string[] | Record<string, unknown> | null>();

const options = ref<Record<string, unknown>[]>([]);
let defaultFilter: (
  value: string,
  update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
) => void;

const props = withDefaults(
  defineProps<{
    id?: string;
    label?: string;
    option: T[];
    optionLabel?: keyof T | string;
    optionValue?: keyof T | string;
    placeholder?: string;

    hideSelected?: boolean;
    readonly?: boolean;
    clearable?: boolean;
    incremental?: boolean;
    fillInput?: boolean;
    disable?: boolean;
    multiple?: boolean;
    hideInput?: boolean;
    hideDropdownIcon?: boolean;

    rules?: ((value: string) => string | true)[];
  }>(),
  {
    option: () => [],
    optionLabel: 'label',
    optionValue: 'value',
    hideSelected: true,
    fillInput: true,
    disable: false,
  },
);

defineEmits<{
  (
    e: 'filter',
    val: string,
    update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
  ): void;
}>();

onMounted(() => {
  defaultFilter = selectFilterOptionRefMod(
    ref(props.option),
    options,
    typeof props.optionLabel === 'string' ? props.optionLabel : 'label',
  );
});

watch(
  () => props.option,
  () => {
    defaultFilter = selectFilterOptionRefMod(
      ref(props.option),
      options,
      typeof props.optionLabel === 'string' ? props.optionLabel : 'label',
    );
  },
);
</script>
<template>
  <q-select
    :placeholder="placeholder"
    outlined
    :clearable
    :disable
    :use-input="!hideInput"
    emit-value
    map-options
    :multiple
    :use-chips="multiple"
    :hide-selected
    hide-bottom-space
    :fill-input="fillInput && !!model"
    :hide-dropdown-icon="readonly || hideDropdownIcon"
    input-debounce="500"
    :option-value="
      typeof props.optionValue === 'string' ? props.optionValue : 'value'
    "
    :option-label="
      typeof props.optionLabel === 'string' ? props.optionLabel : 'label'
    "
    v-model="model"
    dense
    autocomplete="off"
    :readonly
    :label="label"
    :options="incremental ? option : options"
    :for="`${id}`"
    @filter="
      (val, update) => {
        incremental ? $emit('filter', val, update) : defaultFilter(val, update);
      }
    "
    :rules
    @clear="
      () => {
        multiple ? (model = []) : (model = '');
      }
    "
  >
    <template v-if="$slots.prepend" v-slot:prepend>
      <slot name="prepend"></slot>
    </template>
    <template v-if="$slots.append" v-slot:append>
      <slot name="append"></slot>
    </template>

    <template v-slot:no-option>
      <slot name="no-option"></slot>

      <q-item v-if="!$slots.noOption">
        <q-item-section class="text-grey">
          {{ $t('general.noData') }}
        </q-item-section>
      </q-item>
    </template>

    <template
      v-if="$slots.selectedItem || $slots['selected-item']"
      v-slot:selected-item="scope"
    >
      <slot name="selected-item" :scope="scope" :opt="scope.opt as T"></slot>
    </template>

    <template v-if="$slots.option" v-slot:option="scope">
      <slot name="option" :scope="scope" :opt="scope.opt as T"></slot>
    </template>

    <template v-if="$slots['before-options']" #before-options>
      <slot name="before-options"></slot>
    </template>
  </q-select>
</template>
