<script>
import theme from "#build/b24ui/select";
</script>

<script setup>
import { useTemplateRef, computed, onMounted, toRef } from "vue";
import { Primitive, SelectRoot, SelectArrow, SelectTrigger, SelectPortal, SelectContent, SelectViewport, SelectValue as RSelectValue, SelectLabel, SelectGroup, SelectItem as RSelectItem, SelectItemIndicator, SelectItemText, SelectSeparator } from "reka-ui";
import { defu } from "defu";
import { reactivePick } from "@vueuse/core";
import { useAppConfig } from "#imports";
import { useComponentProps } from "../composables/useComponentProps";
import { useForwardProps } from "../composables/useForwardProps";
import { useFieldGroup, FieldGroupReset } from "../composables/useFieldGroup";
import { useComponentIcons } from "../composables/useComponentIcons";
import { useFormField } from "../composables/useFormField";
import { usePortal } from "../composables/usePortal";
import { get, getDisplayValue, isArrayOfArray, looseToNumber } from "../utils";
import { tv } from "../utils/tv";
import icons from "../dictionary/icons";
import B24Badge from "./Badge.vue";
import B24Avatar from "./Avatar.vue";
import B24Chip from "./Chip.vue";
defineOptions({ inheritAttrs: false });
const _props = defineProps({
  id: { type: String, required: false },
  placeholder: { type: String, required: false },
  color: { type: null, required: false },
  size: { type: null, required: false },
  noPadding: { type: Boolean, required: false },
  noBorder: { type: Boolean, required: false },
  underline: { type: Boolean, required: false },
  rounded: { type: Boolean, required: false },
  tag: { type: String, required: false },
  tagColor: { type: null, required: false },
  trailingIcon: { type: [Function, Object], required: false },
  selectedIcon: { type: [Function, Object], required: false },
  content: { type: Object, required: false },
  arrow: { type: [Boolean, Object], required: false },
  portal: { type: [Boolean, String], required: false, skipCheck: true, default: true },
  valueKey: { type: null, required: false, default: "value" },
  labelKey: { type: null, required: false, default: "label" },
  descriptionKey: { type: null, required: false, default: "description" },
  items: { type: null, required: false },
  defaultValue: { type: null, required: false },
  modelValue: { type: null, required: false },
  modelModifiers: { type: null, required: false },
  multiple: { type: Boolean, required: false },
  highlight: { type: Boolean, required: false },
  autofocus: { type: Boolean, required: false },
  autofocusDelay: { type: Number, required: false, default: 0 },
  class: { type: null, required: false },
  b24ui: { type: Object, required: false },
  open: { type: Boolean, required: false },
  defaultOpen: { type: Boolean, required: false },
  autocomplete: { type: String, required: false },
  disabled: { type: Boolean, required: false },
  name: { type: String, required: false },
  required: { type: Boolean, required: false },
  icon: { type: [Function, Object], required: false },
  avatar: { type: Object, required: false },
  loading: { type: Boolean, required: false },
  trailing: { type: Boolean, required: false }
});
const emits = defineEmits(["change", "blur", "focus", "update:modelValue", "update:open"]);
const slots = defineSlots();
const props = useComponentProps("select", _props);
const appConfig = useAppConfig();
const rootProps = useForwardProps(reactivePick(props, "open", "defaultOpen", "disabled", "autocomplete", "required", "multiple"), emits);
const portalProps = usePortal(toRef(() => props.portal));
const position = computed(() => props.content?.position ?? appConfig.b24ui?.select?.defaultVariants?.position ?? theme.defaultVariants?.position);
const contentProps = toRef(() => defu(props.content, { side: "bottom", sideOffset: 8, collisionPadding: 8, position: position.value }));
const arrowProps = toRef(() => defu(typeof props.arrow === "boolean" ? {} : props.arrow, { width: 20, height: 10 }));
const { emitFormChange, emitFormInput, emitFormBlur, emitFormFocus, size: formFieldSize, color, id, name, highlight, disabled, ariaAttrs } = useFormField(_props);
const { orientation, size: fieldGroupSize } = useFieldGroup(_props);
const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(toRef(() => defu(props, { trailingIcon: icons.chevronDown })));
const selectSize = computed(() => fieldGroupSize.value || formFieldSize.value);
const isItemAligned = computed(() => position.value === "item-aligned");
const isTag = computed(() => {
  return props.tag;
});
const b24ui = computed(() => tv({ extend: tv(theme), ...appConfig.b24ui?.select || {} })({
  color: color.value ?? props.color,
  size: selectSize?.value ?? props.size,
  loading: props.loading,
  rounded: Boolean(props.rounded),
  noPadding: Boolean(props.noPadding),
  noBorder: Boolean(props.noBorder),
  underline: Boolean(props.underline),
  highlight: highlight.value ?? props.highlight,
  leading: Boolean(isLeading.value || !!props.avatar || !!slots.leading),
  trailing: Boolean(isTrailing.value || !!slots.trailing),
  fieldGroup: orientation.value,
  position: position.value
}));
const groups = computed(
  () => props.items?.length ? isArrayOfArray(props.items) ? props.items : [props.items] : []
);
const items = computed(() => groups.value.flatMap((group) => group));
function displayValue(value) {
  if (props.multiple && Array.isArray(value)) {
    const displayedValues = value.map((item) => getDisplayValue(items.value, item, {
      labelKey: props.labelKey,
      valueKey: props.valueKey
    })).filter((v) => v != null && v !== "");
    return displayedValues.length > 0 ? displayedValues.join(", ") : void 0;
  }
  return getDisplayValue(items.value, value, {
    labelKey: props.labelKey,
    valueKey: props.valueKey
  });
}
const triggerRef = useTemplateRef("triggerRef");
function autoFocus() {
  if (props.autofocus) {
    triggerRef.value?.$el?.focus({
      focusVisible: true
    });
  }
}
onMounted(() => {
  setTimeout(() => {
    autoFocus();
  }, props.autofocusDelay);
});
function onUpdate(value) {
  if (props.modelModifiers?.trim && (typeof value === "string" || value === null || value === void 0)) {
    value = value?.trim() ?? null;
  }
  if (props.modelModifiers?.number) {
    value = looseToNumber(value);
  }
  if (props.modelModifiers?.nullable) {
    value ??= null;
  }
  if (props.modelModifiers?.optional && !props.modelModifiers?.nullable && value !== null) {
    value ??= void 0;
  }
  const event = new Event("change", { target: { value } });
  emits("change", event);
  emitFormChange();
  emitFormInput();
}
function onUpdateOpen(value) {
  if (!value) {
    const event = new FocusEvent("blur");
    emits("blur", event);
    emitFormBlur();
  } else {
    const event = new FocusEvent("focus");
    emits("focus", event);
    emitFormFocus();
  }
}
function isSelectItem(item) {
  return typeof item === "object" && item !== null;
}
const viewportRef = useTemplateRef("viewportRef");
defineExpose({
  triggerRef: toRef(() => triggerRef.value?.$el),
  viewportRef: toRef(() => {
    const instance = viewportRef.value;
    return instance && typeof instance === "object" && "$el" in instance ? instance.$el : instance;
  })
});
</script>

<template>
  <Primitive as="div" data-slot="root" :class="b24ui.root({ class: [props.b24ui?.root] })">
    <SelectRoot
      v-slot="{ modelValue, open }"
      :name="name"
      v-bind="rootProps"
      :autocomplete="props.autocomplete"
      :disabled="disabled"
      :default-value="props.defaultValue"
      :model-value="modelValue"
      @update:model-value="onUpdate"
      @update:open="onUpdateOpen"
    >
      <SelectTrigger
        :id="id"
        ref="triggerRef"
        data-slot="base"
        :class="b24ui.base({ class: [props.b24ui?.base, props.class] })"
        v-bind="{ ...$attrs, ...ariaAttrs }"
      >
        <B24Badge
          v-if="isTag"
          data-slot="tag"
          :class="b24ui.tag({ class: props.b24ui?.tag })"
          :color="props.tagColor"
          :label="props.tag"
          size="xs"
        />
        <span v-if="isLeading || !!props.avatar || !!slots.leading" data-slot="leading" :class="b24ui.leading({ class: props.b24ui?.leading })">
          <slot name="leading" :model-value="modelValue" :open="open" :b24ui="b24ui">
            <Component
              :is="leadingIconName"
              v-if="isLeading && leadingIconName"
              data-slot="leadingIcon"
              :class="b24ui.leadingIcon({ class: props.b24ui?.leadingIcon })"
            />
            <B24Avatar
              v-else-if="!!props.avatar"
              :size="props.b24ui?.leadingAvatarSize || b24ui.leadingAvatarSize()"
              v-bind="props.avatar"
              data-slot="leadingAvatar"
              :class="b24ui.leadingAvatar({ class: props.b24ui?.leadingAvatar })"
            />
          </slot>
        </span>

        <template v-for="displayedModelValue in [displayValue(modelValue)]" :key="displayedModelValue">
          <RSelectValue
            :data-slot="displayedModelValue != null ? 'value' : 'placeholder'"
            :class="displayedModelValue != null ? b24ui.value({ class: props.b24ui?.value }) : b24ui.placeholder({ class: props.b24ui?.placeholder })"
          >
            <slot :model-value="modelValue" :open="open" :b24ui="b24ui">
              {{ displayedModelValue ?? (props.placeholder ?? "\xA0") }}
            </slot>
          </RSelectValue>
        </template>

        <span v-if="isTrailing || !!slots.trailing" data-slot="trailing" :class="b24ui.trailing({ class: props.b24ui?.trailing })">
          <slot name="trailing" :model-value="modelValue" :open="open" :b24ui="b24ui">
            <Component
              :is="trailingIconName"
              v-if="trailingIconName"
              data-slot="trailingIcon"
              :class="b24ui.trailingIcon({ class: props.b24ui?.trailingIcon })"
            />
          </slot>
        </span>
      </SelectTrigger>

      <SelectPortal v-bind="portalProps">
        <FieldGroupReset>
          <SelectContent data-slot="content" :class="b24ui.content({ class: props.b24ui?.content })" v-bind="contentProps">
            <slot name="content-top" />

            <component
              :is="isItemAligned ? SelectViewport : 'div'"
              ref="viewportRef"
              role="presentation"
              data-slot="viewport"
              :class="b24ui.viewport({ class: props.b24ui?.viewport })"
            >
              <SelectGroup v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" data-slot="group" :class="b24ui.group({ class: props.b24ui?.group })">
                <template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
                  <SelectLabel v-if="isSelectItem(item) && item.type === 'label'" data-slot="label" :class="b24ui.label({ class: [props.b24ui?.label, item.b24ui?.label, item.class] })">
                    {{ get(item, props.labelKey) }}
                  </SelectLabel>

                  <SelectSeparator v-else-if="isSelectItem(item) && item.type === 'separator'" data-slot="separator" :class="b24ui.separator({ class: [props.b24ui?.separator, item.b24ui?.separator, item.class] })" />

                  <RSelectItem
                    v-else
                    data-slot="item"
                    :class="b24ui.item({ class: [props.b24ui?.item, isSelectItem(item) && item.b24ui?.item, isSelectItem(item) && item.class], colorItem: isSelectItem(item) && item?.color || void 0 })"
                    :disabled="isSelectItem(item) && item.disabled"
                    :value="isSelectItem(item) ? get(item, props.valueKey) : item"
                    @select="isSelectItem(item) && item.onSelect?.($event)"
                  >
                    <slot name="item" :item="item" :index="index" :b24ui="b24ui">
                      <slot name="item-leading" :item="item" :index="index" :b24ui="b24ui">
                        <B24Avatar
                          v-if="isSelectItem(item) && item.avatar"
                          :size="item.b24ui?.itemLeadingAvatarSize || props.b24ui?.itemLeadingAvatarSize || b24ui.itemLeadingAvatarSize()"
                          v-bind="item.avatar"
                          data-slot="itemLeadingAvatar"
                          :class="b24ui.itemLeadingAvatar({ class: [props.b24ui?.itemLeadingAvatar, item.b24ui?.itemLeadingAvatar], colorItem: item?.color })"
                        />
                      </slot>

                      <span data-slot="itemWrapper" :class="b24ui.itemWrapper({ class: [props.b24ui?.itemWrapper, isSelectItem(item) && item.b24ui?.itemWrapper] })">
                        <SelectItemText data-slot="itemLabel" :class="b24ui.itemLabel({ class: [props.b24ui?.itemLabel, isSelectItem(item) && item.b24ui?.itemLabel] })">
                          <slot name="item-label" :item="item" :index="index">
                            {{ isSelectItem(item) ? get(item, props.labelKey) : item }}
                          </slot>
                        </SelectItemText>

                        <span
                          v-if="isSelectItem(item) && (get(item, props.descriptionKey) || !!slots['item-description'])"
                          data-slot="itemDescription"
                          :class="b24ui.itemDescription({ class: [props.b24ui?.itemDescription, isSelectItem(item) && item.b24ui?.itemDescription] })"
                        >
                          <slot
                            name="item-description"
                            :item="item"
                            :index="index"
                          >
                            {{ get(item, props.descriptionKey) }}
                          </slot>
                        </span>
                      </span>

                      <span data-slot="itemTrailing" :class="b24ui.itemTrailing({ class: [props.b24ui?.itemTrailing, isSelectItem(item) && item.b24ui?.itemTrailing], colorItem: isSelectItem(item) && item?.color || void 0 })">
                        <SelectItemIndicator as-child>
                          <Component
                            :is="props.selectedIcon || icons.check"
                            data-slot="itemTrailingIcon"
                            :class="b24ui.itemTrailingIcon({ class: [props.b24ui?.itemTrailingIcon, isSelectItem(item) && item.b24ui?.itemTrailingIcon], colorItem: isSelectItem(item) && item?.color || void 0 })"
                          />
                        </SelectItemIndicator>

                        <slot name="item-trailing" :item="item" :index="index" :b24ui="b24ui">
                          <Component
                            :is="item.icon"
                            v-if="isSelectItem(item) && item.icon"
                            data-slot="itemLeadingIcon"
                            :class="b24ui.itemLeadingIcon({ class: [props.b24ui?.itemLeadingIcon, item.b24ui?.itemLeadingIcon], colorItem: item?.color })"
                          />
                          <B24Chip
                            v-else-if="isSelectItem(item) && item.chip"
                            :size="item.b24ui?.itemLeadingChipSize || props.b24ui?.itemLeadingChipSize || b24ui.itemLeadingChipSize()"
                            inset
                            standalone
                            v-bind="item.chip"
                            data-slot="itemLeadingChip"
                            :class="b24ui.itemLeadingChip({ class: [props.b24ui?.itemLeadingChip, item.b24ui?.itemLeadingChip], colorItem: item?.color })"
                          />
                        </slot>
                      </span>
                    </slot>
                  </RSelectItem>
                </template>
              </SelectGroup>
            </component>

            <slot name="content-bottom" />

            <SelectArrow v-if="!!props.arrow" v-bind="arrowProps" data-slot="arrow" :class="b24ui.arrow({ class: props.b24ui?.arrow })" />
          </SelectContent>
        </FieldGroupReset>
      </SelectPortal>
    </SelectRoot>
  </Primitive>
</template>
