<script setup>
import { computed, ref } from "vue";
import Select from "primevue/select";

const props = defineProps({
  label: { type: String, default: "" },
  modelValue: { type: [String, Number, Object], default: null },
  options: { type: Array, default: () => [] },
  optionLabel: { type: [String, Function], default: undefined },
  optionValue: { type: [String, Function], default: undefined },
  optionGroupLabel: { type: [String, Function], default: undefined },
  optionGroupChildren: { type: [String, Function], default: undefined },
  placeholder: { type: String, default: "" },
  disabled: { type: Boolean, default: false },
  invalid: { type: Boolean, default: false },
  error: { type: String, default: "" },
  required: { type: Boolean, default: false },
  filter: { type: Boolean, default: false },
  showClear: { type: Boolean, default: true },
  fluid: { type: Boolean, default: true },
  size: {
    type: String,
    default: undefined,
    validator: (v) => !v || ["small", "large"].includes(v),
  },
  id: { type: String, default: undefined },
  class: { type: [String, Object, Array], default: "w-full" },
});

const emit = defineEmits([
  "update:modelValue",
  "change",
  "focus",
  "blur",
  "filter",
]);

const fallbackId = ref(
  `base-select-${Math.random().toString(36).slice(2, 11)}`,
);
const selectId = computed(() => props.id ?? fallbackId.value);
const invalidState = computed(() => props.invalid || !!props.error);
const errorId = computed(() => `${selectId.value}-error`);
</script>

<template>
  <div class="flex flex-col" :class="props.class">
    <div v-if="label" class="flex flex-col mb-2">
      <label
        :for="selectId"
        class="block text-surface-950 dark:text-surface-0 text-md font-medium leading-7"
      >
        {{ label
        }}<span v-if="required" class="text-red-500" aria-hidden="true">
          *</span
        >
      </label>
    </div>
    <Select
      :id="selectId"
      :model-value="modelValue"
      :options="options"
      :option-label="optionLabel"
      :option-value="optionValue"
      :option-group-label="optionGroupLabel"
      :option-group-children="optionGroupChildren"
      :placeholder="placeholder"
      :disabled="disabled"
      :invalid="invalidState"
      :aria-invalid="invalidState"
      :aria-describedby="error ? errorId : undefined"
      :filter="filter"
      :show-clear="showClear"
      :fluid="fluid"
      :size="size"
      v-bind="$attrs"
      @update:model-value="emit('update:modelValue', $event)"
      @change="emit('change', $event)"
      @focus="emit('focus', $event)"
      @blur="emit('blur', $event)"
      @filter="emit('filter', $event)"
    >
      <template v-if="$slots.value" #value="slotProps">
        <slot name="value" v-bind="slotProps" />
      </template>
      <template v-if="$slots.option" #option="slotProps">
        <slot name="option" v-bind="slotProps" />
      </template>
      <template v-if="$slots.optiongroup" #optiongroup="slotProps">
        <slot name="optiongroup" v-bind="slotProps" />
      </template>
      <template v-if="$slots.empty" #empty>
        <slot name="empty" />
      </template>
      <template v-if="$slots.emptyfilter" #emptyfilter>
        <slot name="emptyfilter" />
      </template>
    </Select>
    <small v-if="error" :id="errorId" class="text-red-500 mt-1" role="alert">{{
      error
    }}</small>
  </div>
</template>
