<template>
  <div ref="rootRef" class="column no-wrap default-select" :class="attrs.class" :style="attrs.style">
    <div v-if="label || $slots.label" class="q-pl-xs">
      <slot name="label">
        <span>{{ label }}</span>
      </slot>
      <span v-if="required" class="text-negative q-ml-xs">*</span>
    </div>
    <q-select
      ref="selectRef"
      v-model="model"
      v-bind="selectAttrs"
      :error="!!error"
      :error-message="errorMessage"
      :rules
      hide-bottom-space
      :class="inputClass"
      :popup-content-class="popupContentClass"
      :popup-content-style="popupContentStyle"
      @update:model-value="error = null"
    >
      <template v-for="(_, slotName) in $slots" #[slotName]="scope">
        <slot :name="slotName" v-bind="scope" />
      </template>
    </q-select>
  </div>
</template>

<script setup>
import { ref, onBeforeMount, onMounted, onBeforeUnmount, useAttrs, computed } from "vue";

defineOptions({
  inheritAttrs: false,
});

const { label, inputClass, popupContentClass, rules } = defineProps({
  label: {
    type: String,
    default: "",
  },
  rules: {
    type: Array,
    default: () => [],
  },
  inputClass: {
    type: String,
    default: null,
  },
  popupContentClass: {
    type: String,
    default: null,
  },
});

const attrs = useAttrs();

const model = defineModel({ type: [String, Object, Array, Number, null] });
const error = defineModel("error", {
  type: [String, Object, Array, Boolean, null],
});

const rootRef = ref(null);
const selectRef = ref(null);
const required = ref(false);

const selectAttrs = computed(() => {
  // eslint-disable-next-line
  const { class: _, style: __, ...rest } = attrs;
  return rest;
});

const menuWidth = ref(null);

const popupContentStyle = computed(() =>
  menuWidth.value ? { width: menuWidth.value } : void 0,
);

let resizeObserver = null;

onMounted(() => {
  if (!rootRef.value || typeof ResizeObserver === "undefined") return;
  resizeObserver = new ResizeObserver(([entry]) => {
    menuWidth.value = `${entry.contentRect.width}px`;
  });
  resizeObserver.observe(rootRef.value);
});

onBeforeUnmount(() => {
  resizeObserver?.disconnect();
  resizeObserver = null;
});

const errorMessage = computed(() => {
  if (error.value == null) {
    return void 0;
  }
  if (typeof error.value === "boolean") {
    return void 0;
  }
  return String(error.value);
});

onBeforeMount(() => {
  rules.forEach((r) => {
    if (r?.$id === "required") return (required.value = true);
  });
});

defineExpose({
  selectRef,
});
</script>

<style scoped lang="scss">
.default-select {
  min-width: 0;
  max-width: 100%;

  :deep(.q-field__native > span) {
    min-width: 0;
  }
}
</style>
