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

<script setup>
import { useTemplateRef, computed, onMounted, toRef } from "vue";
import { Primitive, SelectRoot, SelectArrow, SelectTrigger, SelectPortal, SelectContent, SelectLabel, SelectGroup, SelectItem as RSelectItem, SelectItemIndicator, SelectItemText, SelectSeparator, useForwardPropsEmits } from "reka-ui";
import { defu } from "defu";
import { reactivePick } from "@vueuse/core";
import { useAppConfig } from "#imports";
import { useFieldGroup } from "../composables/useFieldGroup";
import { useComponentIcons } from "../composables/useComponentIcons";
import { useFormField } from "../composables/useFormField";
import { usePortal } from "../composables/usePortal";
import { get, getDisplayValue, isArrayOfArray } 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 },
  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: null, 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(["update:open", "change", "blur", "focus", "update:modelValue"]);
const slots = defineSlots();
const appConfig = useAppConfig();
const rootProps = useForwardPropsEmits(reactivePick(props, "open", "defaultOpen", "disabled", "autocomplete", "required", "multiple"), emits);
const portalProps = usePortal(toRef(() => props.portal));
const contentProps = toRef(() => defu(props.content, { side: "bottom", sideOffset: 8, collisionPadding: 8, position: "popper" }));
const arrowProps = toRef(() => defu(typeof props.arrow === "boolean" ? {} : props.arrow, { width: 20, height: 10 }));
const { emitFormChange, emitFormInput, emitFormBlur, emitFormFocus, size: formGroupSize, 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 || formGroupSize.value);
const isTag = computed(() => {
  return props.tag;
});
const b24ui = computed(() => tv({ extend: tv(theme), ...appConfig.b24ui?.select || {} })({
  color: color.value,
  size: selectSize?.value,
  loading: props.loading,
  rounded: Boolean(props.rounded),
  noPadding: Boolean(props.noPadding),
  noBorder: Boolean(props.noBorder),
  underline: Boolean(props.underline),
  highlight: highlight.value,
  leading: Boolean(isLeading.value || !!props.avatar || !!slots.leading),
  trailing: Boolean(isTrailing.value || !!slots.trailing),
  fieldGroup: orientation.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) {
  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;
}
defineExpose({
  triggerRef: toRef(() => triggerRef.value?.$el)
});
</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="autocomplete"
      :disabled="disabled"
      :default-value="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 || !!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="!!avatar"
              :size="props.b24ui?.leadingAvatarSize || b24ui.leadingAvatarSize()"
              v-bind="avatar"
              data-slot="leadingAvatar"
              :class="b24ui.leadingAvatar({ class: props.b24ui?.leadingAvatar })"
            />
          </slot>
        </span>

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

        <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">
        <SelectContent data-slot="content" :class="b24ui.content({ class: props.b24ui?.content })" v-bind="contentProps">
          <slot name="content-top" />

          <div
            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="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>
          </div>

          <slot name="content-bottom" />

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