<template>
  <div>
    <div
      :class="`flex w-full items-center ${
        label ? 'justify-between' : 'justify-end'
      }`"
    >
      <div class="flex items-center" v-if="label">
        <!-- label of select field -->
        <label class="block text-sm font-medium text-gray-900">
          {{ label }}
        </label>
        <!-- asterisk sign to render if field is required -->
        <p v-if="isRequired" class="ml-1 text-red-600">*</p>
      </div>
      <button
        v-if="actionBtn"
        :id="getActionIDFn(actionBtn)"
        class="block text-sm font-medium text-indigo-800 hover:underline"
        @click="actionBtnEvent($event)"
      >
        {{ actionBtn }}
      </button>
      <span v-if="hint" class="text-sm text-gray-500">{{ hint }}</span>
    </div>
    <div :class="['relative', inputContainerClass]" ref="inputContainer">
      <div :class="label || actionBtn ? 'mt-1' : ''">
        <input
          ref="c-select-input"
          type="text"
          v-model="selectSearch"
          @click="handleInputClick"
          @focus="handleInputFocus"
          @input="search()"
          @keydown="handleKeydown"
          @keydown.enter.prevent="handleKeydown"
          aria-haspopup="listbox"
          aria-expanded="true"
          aria-labelledby="listbox-label"
          class="h-9 w-full cursor-pointer border py-2 pr-10 text-left text-sm"
          :class="[
            classes,
            !isValidate && 'border-red-300',
            inputClasses,
            customBorderRadius,
            toggleDropdown ? 'pl-10' : 'pl-3',
          ]"
          :disabled="isDisabled"
          autocomplete="off"
          @blur="handleElementBlur"
          :id="id"
          :style="inputStyle"
        />
        <button
          class="absolute top-2.5 right-10 z-100 cursor-pointer"
          :id="id + '_close_button'"
          v-if="showCloseButton && (value == null || value.length == 0)"
          @click.stop="handleCrossClick"
        >
          <c-icon
            name="close"
            type="outline-v2"
            class="h-4 w-4 text-gray-400"
          />
        </button>
        <div
          v-if="!toggleDropdown"
          class="pointer-events-none absolute inset-0 left-3 flex h-9 items-center overflow-hidden pr-10"
        >
          <div
            :class="[
              'flex min-w-0 flex-1 items-center gap-2',
              selectedOptionStyles,
            ]"
          >
            <div
              class="flex shrink-0"
              v-if="!addCheckBox && showImage && !selectSearch && value"
            >
              <c-avatar
                v-if="value.photo"
                size="extraextraextrasmall"
                :image="value.photo"
                :rounded="true"
              ></c-avatar>
              <c-avatar
                v-else
                size="extraextraextrasmall"
                :nameInitials="value.initials"
                :rounded="true"
                :isDynamicallyColored="coloredAvatars"
              ></c-avatar>
            </div>
            <div
              class="flex shrink-0"
              v-if="
                addCheckBox &&
                showImage &&
                !selectSearch &&
                selectedValuesArray &&
                selectedValuesArray.length &&
                selectedValuesArray[0].id
              "
            >
              <c-avatar
                v-if="selectedValuesArray[0].photo"
                size="extraextraextrasmall"
                :image="selectedValuesArray[0].photo"
                :rounded="true"
              ></c-avatar>
              <c-avatar
                v-else
                size="extraextraextrasmall"
                :nameInitials="selectedValuesArray[0].initials"
                :rounded="true"
                :isDynamicallyColored="coloredAvatars"
              ></c-avatar>
            </div>
            <c-icon
              v-if="icon && !showImage && !selectSearch"
              :class="icon.class"
              :name="icon.name"
              :type="icon.type"
              :viewBox="icon.viewBox"
            >
            </c-icon>
            <div
              v-if="addCheckBox"
              class="flex flex-1 items-center overflow-hidden text-sm"
            >
              <p
                class="block truncate"
                v-if="
                  selectedValuesArray.length > 0 &&
                  selectedValuesArray[0].id &&
                  (!selectSearch || selectSearch == '')
                "
              >
                {{ selectedValuesArray[0][renderOptionName] }}
              </p>
              <p v-else>
                {{ !selectSearch || selectSearch == "" ? placeholder : null }}
              </p>
              <p
                v-if="
                  selectedValuesArray.length > 1 &&
                  (!selectSearch || selectSearch == '') &&
                  selectedValuesArray[0].showExtra
                "
                class="ml-1 block"
              >
                +{{ selectedValuesArray.length - 1 }}
              </p>
            </div>
            <div v-else class="flex min-w-0 flex-1 items-center gap-3">
              <p
                :class="[
                  'min-w-0 flex-1 truncate text-sm text-left',
                  showImage ? 'ml-3' : '',
                  selectedValueClass,
                ]"
                v-bind:style="{
                  ...(shouldShowCustomFonts
                    ? { fontFamily: selectedValue }
                    : {}),
                }"
              >
                {{
                  hasSelectedValue
                    ? selectedValue
                    : !selectSearch || selectSearch == ""
                    ? placeholder
                    : null
                }}
              </p>
              <c-tag
                v-if="value && value.badge"
                :label="value.badge.label"
                :color="value.badge.color"
                class="shrink-0"
              ></c-tag>
            </div>
          </div>
        </div>
        <div
          v-if="toggleDropdown"
          class="pointer-events-none absolute inset-0 left-3 flex h-9 items-center overflow-hidden pr-10"
        >
          <div class="flex items-center gap-2">
            <c-icon
              name="search"
              type="outline"
              class="h-5 w-5 text-gray-400"
            ></c-icon>
            <p v-if="!selectSearch" class="text-sm text-gray-500">Search</p>
          </div>
        </div>
        <div class="pointer-events-none absolute top-2 right-3 flex">
          <div
            v-if="type == 'tertiary' ? showFocus : true"
            class="pointer-events-none right-0 flex items-center"
          >
            <c-icon
              name="chevron-down"
              type="solid"
              :class="[
                'h-5 w-5 transition-transform duration-300',
                toggleDropdown ? 'rotate-180' : '',
                dropdownSelectorIconClass,
              ]"
            ></c-icon>
          </div>
        </div>
      </div>
      <transition
        enter-active-class="transition ease-out duration-100"
        enter-class="transform opacity-0 scale-95"
        enter-to-class="transform opacity-100 scale-100"
        leave-active-class="transition ease-in duration-75"
        leave-class="transform opacity-100 scale-100"
        leave-to-class="transform opacity-0 scale-95"
      >
        <div
          v-if="toggleDropdown && !isDisabled"
          :class="`${getDropdownPosition()} ${
            useSticky ? 'sticky sm:absolute' : 'absolute'
          } z-10 ${
            isFooter && shouldOpenAbove
              ? 'mb-12 max-h-60'
              : !isFooter && shouldOpenAbove
              ? 'mb-1 max-h-60'
              : 'mt-1 max-h-80 pb-20'
          } ${customWidth ? customWidth : 'w-full'}`"
        >
          <ul
            tabindex="-1"
            role="listbox"
            aria-labelledby="listbox-label"
            ref="optionsList"
            :class="`max-h-60 overflow-auto overscroll-contain bg-white py-1 text-sm ring-1 ring-gray-900 ring-opacity-5 focus:outline-none ${getDropdownPosition2()} ${getDropdownShadow()} ${
              isFooter ||
              (showCreateOption &&
                showCreateOptionAfterSearch &&
                selectSearch &&
                selectSearch.trim())
                ? 'rounded-t-md'
                : 'rounded-md'
            }`"
            @mousedown="handlePreventBlur"
          >
            <li
              v-if="addAction"
              @mousedown="actionEvent($event)"
              class="relative flex min-h-[36px] cursor-pointer select-none py-2 pl-3 pr-9 text-indigo-500 hover:bg-indigo-100 hover:text-indigo-700"
            >
              <c-icon
                type="outline"
                class="mr-1 h-5 w-5 text-indigo-400 group-hover:text-indigo-500"
                name="plus"
              ></c-icon>
              {{ addAction.label }}
            </li>
            <li v-if="headerSwitch" class="min-h-[36px] p-2 hover:bg-gray-100">
              <c-switch
                :label="headerSwitch.headerText"
                class="text-sm"
                direction="left"
                size="small"
                :value="headerSwitch.headerSwitchValue ? 1 : 0"
                @returnToggleValue="handleHeaderSwitch"
                :disabled="headerSwitch.headerSwitchDisable"
              ></c-switch>
            </li>
            <hr v-if="headerSwitch" class="my-1" />
            <!-- Select All Option -->
            <template
              v-if="
                (selectCheckboxes || addCheckBox) &&
                (organizedOptions.groups.length > 0 ||
                  organizedOptions.selectedValues.length > 0 ||
                  organizedOptions.unselectedValues.length > 0)
              "
            >
              <li
                @mousedown="handleSelect($event, allOption)"
                class="relative flex min-h-[36px] cursor-pointer select-none items-center gap-3 py-2 pl-3 pr-9 text-gray-700 hover:bg-gray-100"
              >
                <input
                  type="checkbox"
                  name="select-all"
                  class="pointer-events-none h-4 w-4 cursor-pointer rounded border-gray-300 text-indigo-600 focus:ring-indigo-500 disabled:opacity-50"
                  :checked="selectAll"
                />

                <div class="flex items-center gap-2">
                  <c-icon
                    v-if="allOption && allOption.icon"
                    :class="allOption.icon.class"
                    :name="allOption.icon.name"
                    :type="allOption.icon.type"
                    :viewBox="allOption.icon.viewBox"
                  ></c-icon>
                  <span class="list-options block break-words font-normal">
                    Select all
                  </span>
                </div>
              </li>
              <hr class="my-1" />
            </template>
            <!-- Groups Section -->
            <li
              v-for="(option, index) in organizedOptions.groups"
              :key="`group-${option.id || index}`"
              id="listbox-option-group"
              role="option"
              :ref="`option-group-${String(index)}`"
              @mousedown="handleSelect($event, option)"
              :class="option.isDisabled ? 'pointer-events-none' : ''"
            >
              <span
                class="flex min-h-[36px] w-full items-center gap-3 px-3 py-2"
                :class="`group ${
                  option.isDisabled ? 'custom-disabled-state' : ''
                } ${optionClasses}  relative cursor-pointer select-none text-gray-700 hover:bg-gray-100`"
              >
                <div v-if="addCheckBox" class="flex h-5 shrink-0 items-center">
                  <input
                    type="checkbox"
                    name="group"
                    class="pointer-events-none h-4 w-4 cursor-pointer rounded border-gray-300 text-indigo-600 focus:ring-indigo-500 disabled:opacity-50"
                    :checked="isChecked(option)"
                  />
                </div>
                <div class="flex min-w-0 flex-1 items-start gap-2">
                  <div v-if="option.showImage" class="shrink-0 pt-0.5">
                    <c-avatar
                      v-if="option.photo"
                      size="extraextraextrasmall"
                      :image="option.photo"
                      :rounded="true"
                    ></c-avatar>
                    <c-avatar
                      v-else
                      size="extraextraextrasmall"
                      :nameInitials="option.initials"
                      :rounded="true"
                      :isDynamicallyColored="coloredAvatars"
                    ></c-avatar>
                  </div>
                  <div
                    class="flex shrink-0 items-center justify-center rounded-full bg-gray-100 p-1"
                    v-if="option.showIcon && option.icon"
                  >
                    <c-icon
                      :class="option.icon.class"
                      :name="option.icon.name"
                      :type="option.icon.type"
                      :viewBox="option.icon.viewBox"
                    >
                    </c-icon>
                  </div>
                  <span
                    :class="[
                      option.photo || option.initials ? '' : 'text-left',
                      addCheckBox ? 'overflow-hidden' : '',
                    ]"
                    class="list-options min-w-0 flex-1 break-words font-normal"
                    v-bind:style="{
                      ...(shouldShowCustomFonts
                        ? { fontFamily: option[renderOptionName] }
                        : {}),
                    }"
                    >{{ option[renderOptionName] }}
                  </span>
                </div>
                <c-icon
                  v-if="!addCheckBox && isOptionSelected(option)"
                  name="check-outline-v2"
                  type="outline-v2"
                  class="h-4 w-4 shrink-0 self-center text-indigo-700"
                />
              </span>
            </li>
            <hr
              v-if="
                organizedOptions.groups.length > 0 &&
                (organizedOptions.selectedValues.length > 0 ||
                  organizedOptions.unselectedValues.length > 0)
              "
              class="my-1"
            />
            <!-- Selected values section (non-groups) -->
            <li
              v-for="(option, index) in organizedOptions.selectedValues"
              :key="`selected-value-${option.id || index}`"
              :id="`listbox-option-selected-value-${String(index)}`"
              role="option"
              :ref="`option-selected-value-${String(index)}`"
              @mousedown="handleSelect($event, option)"
              :class="option.isDisabled ? 'pointer-events-none' : ''"
            >
              <span
                class="flex min-h-[36px] w-full items-center gap-3 px-3 py-2"
                :class="`group ${
                  option.isDisabled ? 'custom-disabled-state' : ''
                } ${optionClasses}  relative cursor-pointer select-none text-gray-700 hover:bg-gray-100`"
              >
                <div v-if="addCheckBox" class="flex h-5 shrink-0 items-center">
                  <input
                    type="checkbox"
                    name="value"
                    class="pointer-events-none h-4 w-4 cursor-pointer rounded border-gray-300 text-indigo-600 focus:ring-indigo-500 disabled:opacity-50"
                    :checked="preservedOrder ? isChecked(option) : true"
                  />
                </div>
                <div class="flex min-w-0 flex-1 items-start gap-2">
                  <div v-if="option.showImage" class="shrink-0 pt-0.5">
                    <c-avatar
                      v-if="option.photo"
                      size="extraextraextrasmall"
                      :image="option.photo"
                      :rounded="true"
                    ></c-avatar>
                    <c-avatar
                      v-else
                      size="extraextraextrasmall"
                      :nameInitials="option.initials"
                      :rounded="true"
                      :isDynamicallyColored="coloredAvatars"
                    ></c-avatar>
                  </div>
                  <div
                    class="flex shrink-0 items-center justify-center rounded-full bg-gray-100 p-1"
                    v-if="option.showIcon && option.icon"
                  >
                    <c-icon
                      :class="option.icon.class"
                      :name="option.icon.name"
                      :type="option.icon.type"
                      :viewBox="option.icon.viewBox"
                    >
                    </c-icon>
                  </div>
                  <span
                    :class="[
                      option.photo || option.initials ? '' : 'text-left',
                      addCheckBox ? 'overflow-hidden' : '',
                    ]"
                    class="list-options min-w-0 flex-1 break-words font-normal"
                    v-bind:style="{
                      ...(shouldShowCustomFonts
                        ? { fontFamily: option[renderOptionName] }
                        : {}),
                    }"
                    >{{ option[renderOptionName] }}
                  </span>
                </div>
              </span>
              <hr v-if="option.isBorder" class="my-1" />
            </li>
            <hr
              v-if="
                organizedOptions.selectedValues.length > 0 &&
                organizedOptions.unselectedValues.length > 0
              "
              class="my-1"
            />
            <!-- Unselected values section -->
            <li
              v-for="(option, index) in organizedOptions.unselectedValues"
              :key="`unselected-value-${option.id || index}`"
              :id="`listbox-option-unselected-value-${String(index)}`"
              role="option"
              :ref="`option-unselected-value-${String(index)}`"
              @mousedown="handleSelect($event, option)"
              :class="option.isDisabled ? 'pointer-events-none' : ''"
            >
              <span
                class="flex min-h-[36px] w-full items-center gap-3 px-3 py-2"
                :class="`group ${
                  option.isDisabled ? 'custom-disabled-state' : ''
                } ${optionClasses}  relative cursor-pointer select-none text-gray-700 hover:bg-gray-100`"
              >
                <div v-if="addCheckBox" class="flex h-5 shrink-0 items-center">
                  <input
                    type="checkbox"
                    name="value"
                    class="pointer-events-none h-4 w-4 cursor-pointer rounded border-gray-300 text-indigo-600 focus:ring-indigo-500 disabled:opacity-50"
                    :checked="selectAll || isChecked(option)"
                  />
                </div>
                <div class="flex min-w-0 flex-1 items-start gap-2">
                  <div v-if="option.showImage" class="shrink-0 pt-0.5">
                    <c-avatar
                      v-if="option.photo"
                      size="extraextraextrasmall"
                      :image="option.photo"
                      :rounded="true"
                    ></c-avatar>
                    <c-avatar
                      v-else
                      size="extraextraextrasmall"
                      :nameInitials="option.initials"
                      :rounded="true"
                      :isDynamicallyColored="coloredAvatars"
                    ></c-avatar>
                  </div>
                  <div
                    class="flex shrink-0 items-center justify-center rounded-full bg-gray-100 p-1"
                    v-if="option.showIcon && option.icon"
                  >
                    <c-icon
                      :class="option.icon.class"
                      :name="option.icon.name"
                      :type="option.icon.type"
                      :viewBox="option.icon.viewBox"
                    >
                    </c-icon>
                  </div>
                  <div
                    class="list-options flex min-w-0 flex-1 flex-wrap items-center gap-2 font-normal"
                  >
                    <span
                      :class="[
                        option.photo || option.initials ? '' : 'text-left',
                        addCheckBox ? 'overflow-hidden' : '',
                      ]"
                      class="min-w-0 flex-1 break-words"
                      v-bind:style="{
                        ...(shouldShowCustomFonts
                          ? { fontFamily: option[renderOptionName] }
                          : {}),
                      }"
                      >{{ option[renderOptionName] }}</span
                    >
                    <c-tag
                      v-if="option.badge"
                      :label="option.badge.label"
                      :color="option.badge.color"
                      class="shrink-0"
                    ></c-tag>
                  </div>
                </div>
                <c-icon
                  v-if="!addCheckBox && isOptionSelected(option)"
                  name="check-outline-v2"
                  type="outline-v2"
                  class="h-4 w-4 shrink-0 self-center text-indigo-700"
                />
              </span>
              <hr v-if="option.isBorder" class="my-1" />
            </li>
            <li
              v-if="
                organizedOptions.groups.length === 0 &&
                organizedOptions.selectedValues.length === 0 &&
                organizedOptions.unselectedValues.length === 0 &&
                selectSearch &&
                selectSearch.length > 0
              "
              class="px-3 py-2 text-sm text-gray-500"
            >
              No options found, try searching something else.
            </li>
          </ul>
          <div
            v-if="isFooter"
            class="group cursor-pointer rounded-b-md bg-gray-50 p-3 ring-1 ring-gray-900 ring-opacity-5"
            @mousedown="handleFooter"
          >
            <p class="text-sm text-indigo-700">
              {{ footerText }}
            </p>
          </div>
          <div
            v-if="
              showCreateOption &&
              showCreateOptionAfterSearch &&
              selectSearch &&
              selectSearch.trim()
            "
            class="sticky bottom-0 z-10 flex min-h-[44px] items-start gap-3 rounded-b-md bg-white px-3 py-2 shadow-lg ring-1 ring-gray-900 ring-opacity-5"
          >
            <span class="word-break flex-1 text-sm text-gray-700">{{
              selectSearch
            }}</span>

            <button
              type="button"
              :id="id + '_create_button'"
              @mousedown="handleCreateOption($event)"
              class="flex items-center gap-1 text-sm text-indigo-700"
            >
              <c-icon
                type="solid"
                name="plus-circle-solid-v2"
                class="h-5 w-5 text-indigo-600"
                viewBox="0 0 24 24"
              ></c-icon>
              Create
            </button>
          </div>
        </div>
      </transition>
    </div>
    <p
      v-if="helpText && isValidate == true"
      class="mt-2 text-left text-sm text-gray-500"
    >
      {{ helpText }}
    </p>
    <!-- validation error message -->
    <p
      v-if="!isValidate && errorMessage"
      class="mt-2 text-left text-sm text-red-600"
    >
      {{ errorMessage }}
    </p>
  </div>
</template>
<script>
import { isNumber, isEmpty } from "lodash-es";
import CIcon from "../CIcon/CIcon.vue";
import { getActionID } from "../../helper";
import CTag from "../CTag/CTag.vue";
import CAvatar from "../CAvatar/CAvatar.vue";
export default {
  name: "CSelect",
  components: {
    CIcon,
    CTag,
    CAvatar,
  },
  props: {
    // id of selectpicker
    id: {
      type: String,
    },
    // label of selectpicker
    label: {
      type: String,
    },
    // action button of selectpicker
    actionBtn: {
      type: String,
      default: null,
    },
    // placeholder in selectpicker
    placeholder: {
      type: String,
    },
    // list to render in dropdown
    options: {
      type: Array,
      required: true,
    },
    // show the avatars with different colors
    coloredAvatars: {
      type: Boolean,
    },
    // text below dropdown to describe more about the field
    helpText: {
      type: String,
    },
    // implement a fixed btn at the bottom of dropdown
    isFooter: {
      type: Boolean,
    },
    // style input field
    inputStyle: {
      type: String,
    },
    // footer btn text
    footerText: {
      type: String,
    },
    // text adjacent to label of dropdown to provide hint about field
    hint: { type: String },
    // to show if image is present along with dropdown option
    showImage: { type: Boolean },
    // whether the select field is mandatory or not
    isRequired: {
      type: Boolean,
    },
    // validation is passed or not
    isValidate: { type: Boolean, default: true },
    // will truncate the text in input field
    selectedOptionStyles: {
      type: String,
    },
    // validation error message
    errorMessage: {
      type: String,
    },
    // perform action on first option in dropdown
    addAction: { type: Object },
    // icons in dropdown list
    icon: { type: Object },
    // value to set as default option in dropdown
    value: { type: [Object, String, Array], default: null },
    // type of dropdown - gray,tertiary, blue or default
    type: {
      type: String,
    },
    //  name of the field in array to that contains text to render in dropdown
    renderOptionName: {
      type: String,
      default: "option",
    },
    // whether to disable the selectpicker
    isDisabled: {
      type: Boolean,
      default: false,
    },
    inputClasses: {
      type: String,
      default: "",
    },
    optionClasses: {
      type: String,
      default: "",
    },
    // customised width for the dropdown
    customWidth: {
      type: String,
      default: null,
    },
    customBorderRadius: {
      type: String,
      default: "rounded-md",
    },
    addCheckBox: {
      type: Boolean,
      default: false,
    },
    selectAll: {
      type: Boolean,
      default: false,
    },
    selectCheckboxes: {
      type: Boolean,
      default: false,
    },
    headerSwitch: {
      type: Object,
      default: null,
    },
    useSticky: {
      type: Boolean,
      default: false,
    },
    showCloseButton: {
      type: Boolean,
      default: false,
    },
    showCreateOption: {
      type: Boolean,
      default: false,
    },
    shouldShowCustomFonts: {
      type: Boolean,
      default: false,
    },
    customFontNames: {
      type: Array,
      default: () => [],
    },
    inputContainerClass: {
      type: String,
      default: "",
    },
  },
  data() {
    return {
      toggleDropdown: false,
      selectedValue: null,
      showFocus: false,
      selectSearch: null,
      renderOptions: this.options,
      selectedValuesArray: [],
      isToggle: 0,
      shouldOpenAbove: false,
      // Frozen order while dropdown is open - prevents UI shift on selection
      preservedOrder: null,
    };
  },
  computed: {
    classes() {
      return {
        "text-gray-900 border border-gray-300 hover:bg-gray-200 bg-gray-100 focus:ring-2 focus:border-gray-200 focus:ring-gray-200 focus:ring-offset-2 shadow-sm":
          this.type == "gray",
        "bg-white border border-gray-300 hover:bg-indigo-100 text-indigo-600 hover:text-indigo-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-200":
          this.type == "tertiary",
        "bg-white text-indigo-700 border-none focus:outline-none":
          this.type == "indigo",
        "border border-gray-300 bg-white shadow-sm focus:outline-none focus:border-gray-300 focus:ring-indigo-600 focus:ring-2 focus:ring-offset-2":
          this.type == null,
      };
    },
    allOption() {
      if (
        this.options &&
        this.options.length > 0 &&
        this.options[0] &&
        this.options[0].id === "all"
      ) {
        return this.options[0];
      }
      return null;
    },
    organizedOptions() {
      if (!this.addCheckBox) {
        const filteredOptions = this.renderOptions.filter(
          (option) => option.id !== "all"
        );
        return {
          groups: [],
          selectedValues: [],
          unselectedValues: filteredOptions,
        };
      }

      // While dropdown is open and not searching, preserve order to prevent UI shift on selection
      if (
        this.preservedOrder &&
        (!this.selectSearch || this.selectSearch.trim() === "")
      ) {
        return this.preservedOrder;
      }

      return this.computeOrganizedOptions();
    },
    showCreateOptionAfterSearch() {
      if (!this.showCreateOption) return false;

      const term = (this.selectSearch || "").trim().toLowerCase();
      if (!term) return false;

      const hasExactMatch = this.options.some((option) => {
        const label = option[this.renderOptionName];
        return label && String(label).toLowerCase() === term;
      });

      return !hasExactMatch;
    },
    dropdownSelectorIconClass() {
      return this.type === "indigo" ? "text-indigo-600" : "text-gray-400";
    },
    hasSelectedValue() {
      const val = this.selectedValue;
      if (val === null || val === undefined || val === "") {
        return false;
      }
      if (typeof val === "object") {
        return !isEmpty(val);
      }
      return true;
    },
    selectedValueClass() {
      if (this.hasSelectedValue) {
        if (this.isDisabled) {
          return "text-gray-500";
        }

        if (this.type === "indigo") {
          return "text-indigo-600";
        }
        return "text-gray-700";
      }
      return "text-gray-500";
    },
  },
  methods: {
    isEmpty,
    getActionIDFn(name) {
      return getActionID(name, this.id);
    },
    checkAvailableSpace() {
      if (!this.$refs.inputContainer) return false;

      const container = this.$refs.inputContainer;
      const rect = container.getBoundingClientRect();
      const viewportHeight = window.innerHeight;
      const bottomSpace = viewportHeight - rect.bottom;
      const componentHeight = 320;

      // Check if bottom space is less than 80% the component height if there is no footer
      return (
        bottomSpace <
        (this.isFooter ? componentHeight : (componentHeight * 4) / 5)
      );
    },
    getDropdownPosition() {
      this.shouldOpenAbove = this.checkAvailableSpace();
      return this.shouldOpenAbove ? "bottom-full" : "top-full";
    },
    getDropdownPosition2() {
      return this.shouldOpenAbove ? "bottom-full" : "";
    },
    getDropdownShadow() {
      if (this.shouldOpenAbove) {
        return "shadow-[0_-10px_15px_-3px_rgba(0,0,0,0.1),0_-4px_6px_-4px_rgba(0,0,0,0.1)]";
      } else {
        return "shadow-lg";
      }
    },
    handleCrossClick(event) {
      event.preventDefault();
      this.$emit("hide-single-select-dropdown");
    },
    handleInputClick() {
      this.toggleDropdown = !this.toggleDropdown;
      if (!this.toggleDropdown) {
        this.selectSearch = "";
        this.$nextTick(() => {
          if (this.$refs["c-select-input"]) {
            this.$refs["c-select-input"].focus();
          }
        });
      }
    },
    handleInputFocus() {
      if (this.type == "tertiary") {
        this.showFocus = true;
      }
    },
    handleSelect(event, option) {
      this.selectSearch = null;
      this.selectedValue = option[this.renderOptionName];
      if (this.addCheckBox) {
        // Freeze current display order BEFORE updating selection to prevent UI shift
        const currentDisplay = this.organizedOptions;
        this.preservedOrder = {
          groups: [...currentDisplay.groups],
          selectedValues: [...currentDisplay.selectedValues],
          unselectedValues: [...currentDisplay.unselectedValues],
        };
        if (this.getIndex(option) == -1) {
          this.selectedValuesArray = [...this.selectedValuesArray, option];
        } else {
          this.selectedValuesArray = this.selectedValuesArray.filter(
            (item) => option.id !== item.id
          );
        }
        this.$emit("onChangeChecked", this.selectedValuesArray, option);
      }

      this.$emit("onChangeValue", option);
      if (!this.addCheckBox) {
        this.toggleDropdown = false;
      }
      this.type === "tertiary" ? (this.showFocus = false) : "";
      this.renderOptions = this.options;
    },
    handleFooter() {
      this.$emit("handleFooter");
    },
    actionEvent(event) {
      this.$emit("listAction", event);
    },
    actionBtnEvent(event) {
      this.$emit("listAction", event);
    },
    handleElementBlur() {
      this.toggleDropdown = false;
      if (this.addCheckBox) {
        this.$emit("onClickOutside", this.selectedValuesArray);
      }
      this.selectSearch = null;
      this.renderOptions = this.options;
    },
    handleHeaderSwitch(value) {
      this.$emit("handleHeaderSwitch", value);
    },
    //this prevents the blur to be called when the user clicks on the scrollbar
    handlePreventBlur(event) {
      event.preventDefault();
    },
    search() {
      this.selectedValue = null;
      // if the search term is empty space, then set the render options to empty array
      if (
        this.selectSearch !== null &&
        this.selectSearch.length > 0 &&
        this.selectSearch.trim() === ""
      ) {
        this.renderOptions = [];
        this.$emit("search-term", this.selectSearch);
        return;
      }
      if (
        !this.selectSearch ||
        this.selectSearch == "" ||
        this.selectSearch.trim() == ""
      ) {
        this.renderOptions = this.options;
        this.$emit("search-term", this.selectSearch);
        return;
      }
      let options = [...this.options];
      this.renderOptions = options.filter((option) => {
        isNumber(option[this.renderOptionName])
          ? (option[this.renderOptionName] =
              option[this.renderOptionName].toString())
          : "";
        const optionName = String(
          option[this.renderOptionName] || ""
        ).toLowerCase();
        const searchTerm = this.selectSearch.trim().toLowerCase();
        return optionName.includes(searchTerm);
      });

      if (this.renderOptions.length === 0) {
        this.$emit("search-term", this.selectSearch.trim());
      }
    },
    async scrollOptionIntoView(refName) {
      await this.$nextTick();
      const list = this.$refs.optionsList;
      const optionEl = (this.$refs[refName] || [])[0];
      if (!list || !optionEl) return;

      const top = optionEl.offsetTop;
      const bottom = top + optionEl.offsetHeight;
      const viewTop = list.scrollTop;
      const viewBottom = viewTop + list.clientHeight;

      const target =
        top < viewTop
          ? top
          : bottom > viewBottom
          ? bottom - list.clientHeight
          : viewTop;

      if (target !== viewTop) {
        list.scrollTo({ top: target, behavior: "smooth" });
      }
    },
    isOptionSelected(option) {
      /*
       * Compares value to option by id when both exist,
       * otherwise by renderOptionName / string value.
       */
      if (option == null) {
        return false;
      }

      const v = this.value;
      if (v === null) {
        return false;
      }

      if (typeof v === "object" && v !== null) {
        if (v.id !== undefined && option.id !== undefined) {
          return v.id === option.id;
        }

        const vLabel = v[this.renderOptionName];
        if (vLabel !== undefined && vLabel !== null) {
          return String(vLabel) === String(option[this.renderOptionName]);
        }
      }

      return String(v) === String(option[this.renderOptionName]);
    },
    getIndex(option) {
      return this.selectedValuesArray.findIndex((item) => item.id == option.id);
    },
    isChecked(option) {
      return this.selectedValuesArray.findIndex(
        (item) => item.id == option.id
      ) == -1
        ? false
        : true;
    },
    handleCreateOption(event) {
      event.preventDefault();
      this.toggleDropdown = false;
      this.$emit("handleCreateOption", {
        event,
        searchText: this.selectSearch.trim(),
      });
      this.selectSearch = null;
      this.renderOptions = this.options;

      const cSelectInputRef = this.$refs["c-select-input"];
      this.$nextTick(() => {
        cSelectInputRef && cSelectInputRef.blur();
      });
    },
    handleKeydown(event) {
      if (event.key === "Enter") {
        event.preventDefault();
        event.stopPropagation();

        if (
          this.showCreateOption &&
          this.showCreateOptionAfterSearch &&
          this.selectSearch &&
          this.selectSearch.trim()
        ) {
          this.handleCreateOption(event);
        }
      }
    },
    async handleLoadFont() {
      const customFontNames = this.customFontNames;
      const googleParam = customFontNames
        .map((f) => `family=${f.replace(/ /g, "+")}`)
        .join("&");

      const link = document.createElement("link");
      link.rel = "stylesheet";
      link.href = `https://fonts.googleapis.com/css2?${googleParam}&display=swap`;
      link.setAttribute("data-fonts", customFontNames.join(","));
      document.head.appendChild(link);

      await document.fonts.ready;
    },
    isGroup(option) {
      return option.type && option.type.includes("group");
    },
    computeOrganizedOptions() {
      const selectedIds = new Set(
        this.selectedValuesArray.map((item) => item.id)
      );

      const groups = [];
      const selectedValues = [];
      const unselectedValues = [];

      // Filter out the "all" option from renderOptions
      this.renderOptions
        .filter((option) => option.id !== "all")
        .forEach((option) => {
          if (this.isGroup(option)) {
            // Groups stay in their own section regardless of selection
            groups.push(option);
          } else {
            // Values are separated by selection state
            if (selectedIds.has(option.id)) {
              selectedValues.push(option);
            } else {
              unselectedValues.push(option);
            }
          }
        });

      // Sort by renderOptionName (guard against undefined a/b or missing renderOptionName)
      const getSortKey = (item) =>
        String((item && item[this.renderOptionName]) || "").toLowerCase();

      selectedValues.sort((a, b) => getSortKey(a).localeCompare(getSortKey(b)));
      unselectedValues.sort((a, b) =>
        getSortKey(a).localeCompare(getSortKey(b))
      );

      return {
        groups,
        selectedValues,
        unselectedValues,
      };
    },
  },
  watch: {
    value() {
      this.selectedValue =
        this.value !== null && this.value[this.renderOptionName]
          ? this.value[this.renderOptionName]
          : this.value;
      if (this.addCheckBox) {
        this.selectedValuesArray = this.value ? this.value : [];
      }
    },
    options() {
      this.renderOptions = this.options;
    },
    toggleDropdown(newValue) {
      if (newValue) {
        this.checkAvailableSpace();

        this.preservedOrder = null;

        const index = this.renderOptions.findIndex(
          (option) => option[this.renderOptionName] === this.selectedValue
        );
        if (index !== -1) {
          const refName = `option-${String(index)}`;
          this.scrollOptionIntoView(refName);
        }
      } else {
        this.preservedOrder = null;
      }
    },
  },
  mounted() {
    this.selectedValue =
      this.value !== null && this.value[this.renderOptionName]
        ? this.value[this.renderOptionName]
        : this.value;
    if (this.addCheckBox) {
      this.selectedValuesArray = this.value ? this.value : [];
    }

    if (this.shouldShowCustomFonts && this.customFontNames.length > 0) {
      this.handleLoadFont();
    }
  },
};
</script>

<style scoped>
.word-break {
  word-break: break-word;
}
</style>
