<!--
 * Copyright (c) 2022 - present TinyVue Authors.
 * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
 *
 * Use of this source code is governed by an MIT-style license.
 *
 * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
 * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
 * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
 *
 -->

<template>
  <div
    ref="select"
    class="tiny-base-select"
    v-popover:popover
    :class="[
      state.selectSize ? 'tiny-base-select--' + state.selectSize : '',
      state.collapseTags ? 'tiny-base-select__collapse-tags' : '',
      filterable ? 'tiny-base-select__filterable' : '',
      multiple ? 'tiny-base-select__multiple' : '',
      (state.inputHovering || state.visible) && !clickExpand ? 'is-hover' : '',
      state.isDisplayOnly ? 'is-display-only' : '',
      hoverExpand ? 'is-hover-expand' : '',
      clickExpand ? 'is-click-expand' : '',
      state.showCollapseTag ? 'collapse-tag-clicked' : '',
      state.selectDisabled ? 'is-disabled' : '',
      $parent.$attrs.class
    ]"
    @mouseleave.self="
      () => {
        state.selectHover = false
        state.inputHovering = false
      }
    "
    @mouseenter.self="
      () => {
        state.selectHover = true
        state.inputHovering = true
      }
    "
    @click="toggleMenu"
    v-clickoutside="handleClose"
    v-bind="a($attrs, ['class', 'style'], true)"
  >
    <div
      ref="tagsGroup"
      :style="state.selectFiexd"
      :class="['tiny-base-select__tags-group', { 'is-expand': state.isExpand }]"
    >
      <slot name="reference">
        <tiny-filter-box
          v-if="shape === 'filter'"
          ref="reference"
          @click="toggleMenu"
          :show-close="clearable"
          :placeholder="placeholder"
          :disabled="state.selectDisabled"
          :label="label"
          :tip="tip"
          :value="
            multiple
              ? state.selected.map((item) => (item.state ? item.state.currentLabel : item.currentLabel)).join('; ')
              : state.selectedLabel
          "
          :drop-down-visible="state.visible"
          :blank="blank"
        >
        </tiny-filter-box>
        <div
          ref="tags"
          :class="[
            'tiny-base-select__tags',
            { 'is-showicon': slots.prefix, 'not-selected': !state.selected.length },
            { 'is-show-tag': !state.isShowTagText }
          ]"
          v-if="multiple && !state.isDisplayOnly && !shape"
          :style="state.tagsStyle"
        >
          <span v-if="!state.isShowTagText">
            <span v-if="collapseTags && state.selected.length">
              <tiny-tag
                :closable="!state.selectDisabled"
                :size="state.collapseTagSize"
                :hit="state.selected[0].state ? state.selected[0].state.hitState : state.selected[0].hitState"
                :key="state.key"
                :type="state.getTagType"
                @close="deleteTag($event, state.selected[0])"
                disable-transitions
              >
                <tiny-tooltip
                  effect="light"
                  placement="top"
                  @mouseenter.native="handleEnterTag($event, getValueKey(state.selected[0]))"
                >
                  <span class="tiny-base-select__tags-text">
                    <slot name="label" :item="getLabelSlotValue(state.selected[0])">{{
                      state.selected[0].state ? state.selected[0].state.currentLabel : state.selected[0].currentLabel
                    }}</slot>
                  </span>
                  <template #content>
                    <span v-if="state.tooltipContent[getValueKey(state.selected[0])]">
                      <slot name="label" :item="getLabelSlotValue(state.selected[0])">
                        {{
                          state.selected[0].state
                            ? state.selected[0].state.currentLabel
                            : state.selected[0].currentLabel
                        }}
                      </slot>
                    </span>
                  </template>
                </tiny-tooltip>
              </tiny-tag>
              <tiny-tag
                v-if="state.selected.length > 1"
                :closable="false"
                :size="state.collapseTagSize"
                :type="state.getTagType"
                disable-transitions
                class="tiny-base-select__tags-number"
              >
                <span class="tiny-base-select__tags-text">+ {{ state.selected.length - 1 }}</span>
              </tiny-tag>
            </span>
            <!-- 显示所有标签的循环 -->
            <span ref="tags-content" v-if="!collapseTags">
              <!-- 当 showAllTextTag 时， 用all-text属性做为tag。 xdesign规范 -->
              <tiny-tag
                v-if="showAllTextTag && state.selectCls === 'checked-sur'"
                :type="state.getTagType"
                key="tags-all-text-tag"
                data-tag="tags-all-text-tag"
                :disabled="state.isDisabled"
                :closable="true"
                :size="state.collapseTagSize"
                @close="toggleCheckAll(false)"
              >
                {{ allText || t('ui.base.all') }}
              </tiny-tag>
              <!-- 当非 showAllTextTag 时，原来的模式渲染 -->
              <template v-else>
                <tiny-tag
                  v-if="hoverExpand || clickExpand"
                  :class="['tiny-base-select__tags-collapse', { 'is-hidden': state.isHidden || state.isDisabled }]"
                  :type="state.getTagType"
                  key="tags-collapse"
                  data-tag="tags-collapse"
                  only-icon
                  :closable="false"
                  :size="state.collapseTagSize"
                  @click="onClickCollapseTag($event)"
                >
                  <template v-if="hoverExpand"> + {{ state.collapseTagsLength }} </template>
                  <icon-ellipsis v-else></icon-ellipsis>
                </tiny-tag>
                <tiny-tag
                  v-for="(item, index) in state.selected"
                  :key="getValueKey(item)"
                  :class="{
                    'not-visible': state.toHideIndex <= index && !state.isExpand,
                    'is-required': item.required
                  }"
                  :closable="isTagClosable(item)"
                  :disabled="state.isDisabled || item.disabled"
                  :size="state.collapseTagSize"
                  :hit="item.state ? item.state.hitState : item.hitState"
                  :type="state.getTagType"
                  @close="deleteTag($event, item)"
                  disable-transitions
                >
                  <tiny-tooltip
                    effect="light"
                    placement="top"
                    @mouseenter.native="handleEnterTag($event, getValueKey(item))"
                  >
                    <span v-if="!state.visible && state.overflow === index" class="tiny-base-select__tags-text">
                      {{ item.state ? item.state.currentLabel + '... ' : item.currentLabel + '... ' }}
                    </span>
                    <span v-else class="tiny-base-select__tags-text">
                      <slot name="label" :item="getLabelSlotValue(item)">
                        {{ item.state ? item.state.currentLabel : item.currentLabel }}
                      </slot>
                    </span>
                    <template v-if="state.tooltipContent[getValueKey(item)]" #content>
                      <span v-if="!state.visible && state.overflow === index">
                        {{ item.state ? item.state.currentLabel + '... ' : item.currentLabel + '... ' }}
                      </span>
                      <span v-else>
                        <slot name="label" :item="getLabelSlotValue(item)">
                          {{ item.state ? item.state.currentLabel : item.currentLabel }}
                        </slot>
                      </span>
                    </template>
                  </tiny-tooltip>
                </tiny-tag>

                <!-- 收起按钮 -->
                <span
                  v-if="clickExpand && state.showCollapseTag"
                  class="tiny-base-select__collapse-text"
                  @click="onClickCollapseTag($event)"
                >
                  {{ t('ui.select.collapse') }}
                  <icon-chevron-up></icon-chevron-up>
                </span>
              </template>
            </span>
          </span>

          <span v-else class="tiny-base-select__tags-text is-disabled">
            <tiny-tooltip effect="light" placement="top" :disabled="!showTips">
              <span>
                <span v-for="item in state.selected" :key="item.value">
                  <slot name="label" :item="item">{{ item.state ? item.state.currentLabel : item.currentLabel }}</slot
                  >;
                </span>
              </span>

              <template #content>
                <div :class="[state.showTips && 'tiny-base-select__show-tips', 'tiny-base-select__show-common']">
                  <span v-if="slots.label">
                    <span v-for="item in state.selected" :key="getValueKey(item)">
                      <slot name="label" :item="item"></slot>
                    </span>
                  </span>
                  <span v-else>{{ disabledTooltipContent || state.disabledTooltipContent }}</span>
                </div>
              </template>
            </tiny-tooltip>
          </span>
          <!-- tiny 新增：searchable时, 这里不显示 state.query -->
          <input
            ref="input"
            v-show="filterable && !searchable && !state.selectDisabled"
            v-model="state.query"
            type="text"
            class="tiny-base-select__input"
            :class="[state.selectSize ? `is-${state.selectSize}` : '']"
            :disabled="state.selectDisabled"
            :autocomplete="autocomplete"
            @focus="handleFocus"
            @blur="handleBlur"
            @keyup="managePlaceholder"
            @keydown="resetInputState"
            @keydown.down.prevent="navigateOptions('next')"
            @keydown.up.prevent="navigateOptions('prev')"
            @keydown.enter.prevent="selectOption"
            @keydown.esc.stop.prevent="state.visible = false"
            @keydown.delete="deletePrevTag"
            @keydown.tab="state.visible = false"
            @compositionstart="handleComposition"
            @compositionupdate="handleComposition"
            @compositionend="handleComposition"
            @input="debouncedQueryChange"
            :style="{
              'flex-grow': '1',
              width: state.inputLength / (state.inputWidth - 32) + '%',
              'max-width': state.inputWidth - 42 + 'px',
              height: 'auto'
            }"
          />
        </div>
        <tiny-input
          tiny_mode="pc"
          v-if="!shape"
          ref="reference"
          v-model="state.selectedLabel"
          type="text"
          :placeholder="state.currentPlaceholder"
          :name="name"
          :id="id"
          :autocomplete="autocomplete"
          :size="state.selectSize"
          :disabled="state.selectDisabled"
          :readonly="state.readonly"
          :display-only="state.isDisplayOnly"
          :display-only-content="state.displayOnlyContent"
          :unselectable="state.readonly ? 'on' : 'off'"
          :validate-event="false"
          :input-box-type="inputBoxType"
          :class="{
            'is-focus': state.visible,
            overflow: state.overflow,
            'is-show-close': state.showClose
          }"
          :tabindex="multiple && filterable ? '-1' : tabindex"
          @focus="handleFocus"
          @blur="handleBlur"
          @keyup="debouncedOnInputChange"
          @keydown.down.stop.prevent="navigateOptions('next')"
          @keydown.up.stop.prevent="navigateOptions('prev')"
          @keydown.enter.prevent="selectOption"
          @keydown.esc.stop.prevent="state.visible = false"
          @keydown.tab="state.visible = false"
          @paste="debouncedOnInputChange"
          @mouseenter="onMouseenterNative"
          @mouseleave="onMouseleaveNative"
          @compositionend.native="handleComposition"
        >
          <template #prefix v-if="slots.prefix">
            <slot name="prefix"></slot>
          </template>
          <template #suffix>
            <slot name="suffix"></slot>
            <!-- tiny 新增：xdesign 规范 ：多选限制数量时，在后缀显示 "选中/最大限制项" 计数的提示文字  -->
            <span v-if="showLimitText && multiple && multipleLimit" class="tiny-base-select__limit-txt">
              {{ state.selected.length }}/{{ multipleLimit }}
            </span>
            <!-- tiny 新增：xdesign 规范 ： 显示比例时，在后缀显示 "选中/全部项" 计数的提示文字  -->
            <span
              v-else-if="showProportion && state.selected.length > 0 && state.options.length > 1"
              class="tiny-base-select__proportion-txt"
            >
              {{ state.selected.length + '/' + state.options.length }}
            </span>
            <span v-if="state.showCopy" class="tiny-base-select__copy" @click.stop="handleCopyClick">
              <icon-copy class="tiny-svg-size tiny-base-select__caret"></icon-copy>
            </span>

            <icon-close
              v-if="state.showClose"
              class="tiny-svg-size tiny-base-select__caret icon-close"
              @click="handleClearClick"
              @mouseenter="state.inputHovering = true"
            ></icon-close>
            <!-- tiny 新增 自定义getIcon .
              tiny 的 autoHideDownIcon=true, 显示 close时， 不显示向下的箭头。
              aui是同时显示2个。 -->
            <component
              v-show="
                state.autoHideDownIcon
                  ? !state.showClose && !(remote && filterable && !remoteConfig.showIcon)
                  : !(remote && filterable && !remoteConfig.showIcon)
              "
              :is="state.getIcon.icon"
              :class="[
                'tiny-svg-size',
                'tiny-base-select__caret',
                state.iconClass,
                { 'is-reverse': !state.visible && state.getIcon.isDefault },
                { 'not-reverse': !state.getIcon.isDefault }
              ]"
              @click="handleDropdownClick"
            ></component>
          </template>
        </tiny-input>
      </slot>
      <transition name="tiny-zoom-in-top" @before-enter="handleMenuEnter" @after-leave="doDestroy">
        <tiny-select-dropdown
          ref="popper"
          :is-drop-inherit-width="isDropInheritWidth"
          :placement="placement"
          :append-to-body="popperAppendToBody"
          v-show="!onCopying() && !hideDrop && state.visible && state.emptyText !== false"
          :style="dropStyle"
          :popper-options="popperOptions"
        >
          <div
            v-if="shape && filterable"
            class="tiny-base-select__filter-input"
            :class="[remote && !state.options.length ? 'tiny-base-select__remote-input' : '']"
          >
            <tiny-input
              ref="input"
              type="text"
              v-model="state.query"
              :placeholder="placeholder"
              @input="debouncedQueryChange"
              @focus="handleFocus"
              autofocus
            ></tiny-input>
          </div>
          <div v-if="topCreate" class="tiny-select__top-create">
            <div @click="$emit('top-create-click', $event)">
              <component :is="state.designConfig?.icons?.addIcon || 'icon-add-circle'"></component>
              <span>{{ topCreateText }}</span>
            </div>
          </div>
          <slot
            name="panel"
            :methods="{
              updateSelectedData,
              hidePanel
            }"
          ></slot>
          <!-- tiny 新增 可搜索的输入框 -->
          <tiny-input
            v-if="searchable"
            input-box-type="underline"
            v-model="state.query"
            :placeholder="t('ui.search.placeholder')"
            class="tiny-select-dropdown__search"
            @update:modelValue="handleQueryChange(state.query)"
          >
            <template #prefix>
              <!-- tiny 为适配smb，增加前置的放大镜 -->
              <icon-search class="tiny-select-dropdown__search-prefix"></icon-search>
            </template>
            <template #suffix>
              <span v-show="state.query" class="tiny-icon-close">
                <icon-close @click="clearSearchText"></icon-close>
              </span>
              <icon-search class="tiny-select-dropdown__search-suffix"></icon-search>
            </template>
          </tiny-input>

          <template v-if="optimization">
            <div :style="{ height: `${state.optimizeStore.recycleScrollerHeight}px` }">
              <tiny-recycle-scroller
                ref="scrollbar"
                style="height: 100%"
                :key="state.magicKey"
                :key-field="valueField"
                :list-class="['tiny-select-dropdown__wrap']"
                :item-class="['tiny-select-dropdown__item-view']"
                :items="state.datas"
                :item-size="state.optimizeOpts.optionHeight"
                v-show="!state.emptyFlag && !loading"
              >
                <template #before>
                  <tiny-option :value="state.query" created v-if="state.showNewOption"> </tiny-option>
                </template>
                <template #default="{ item }">
                  <slot :item="item">
                    <tiny-option
                      :key="`${item[valueField]}`"
                      :label="item[textField]"
                      :value="item[valueField]"
                      :disabled="item.disabled"
                      :required="item.required"
                      :highlight-class="item._highlightClass"
                      :events="item.events"
                      :icon="item.icon"
                      @mousedown.stop
                    >
                    </tiny-option>
                  </slot>
                </template>
              </tiny-recycle-scroller>
            </div>
          </template>
          <tiny-scrollbar
            v-if="!optimization"
            ref="scrollbar"
            show
            tag="ul"
            :wrap-class="['tiny-select-dropdown__wrap']"
            :view-class="['tiny-select-dropdown__list']"
            @mousedown.stop
            :class="{
              'is-empty': !allowCreate && state.query && state.filteredOptionsCount === 0
            }"
            v-show="state.options.length > 0 && !loading"
          >
            <slot name="dropdown"></slot>
            <li
              v-if="multiple && showCheck && showAlloption && !state.multipleLimit && !state.query && !remote"
              class="tiny-option tiny-option_all tiny-select-dropdown__item"
              data-tag="tiny-option"
              :class="[
                {
                  hover: state.hoverIndex === -9 && state.selectCls !== 'checked-sur'
                },
                { 'selected': state.selectCls === 'checked-sur' }
              ]"
              @click.stop="toggleCheckAll(false)"
              @mousedown.stop
              @mouseenter="state.hoverIndex = -9"
            >
              <component :is="`icon-${state.selectCls}`" :class="['tiny-svg-size', state.selectCls]" />
              <span>{{ allText || t('ui.base.all') }}</span>
            </li>
            <li
              v-if="
                multiple &&
                showCheck &&
                showAlloption &&
                !state.multipleLimit &&
                state.query &&
                !state.emptyText &&
                !remote
              "
              class="tiny-option tiny-select-dropdown__item"
              data-tag="tiny-option"
              :class="[
                {
                  hover: state.hoverIndex === -9 && state.filteredSelectCls !== 'checked-sur'
                },
                { 'selected': state.filteredSelectCls === 'checked-sur' }
              ]"
              @click.stop="toggleCheckAll(true)"
              @mousedown.stop
              @mouseenter="state.hoverIndex = -9"
            >
              <component :is="`icon-${state.filteredSelectCls}`" :class="['tiny-svg-size', state.filteredSelectCls]" />
              <span>{{ allText || t('ui.base.all') }}</span>
            </li>
            <tiny-option :value="state.query" created v-if="state.showNewOption"> </tiny-option>
            <slot>
              <tiny-option
                v-for="item in state.datas"
                :key="`${item[valueField]}`"
                :label="item[textField]"
                :value="item[valueField]"
                :disabled="item.disabled"
                :required="item.required"
                :highlight-class="item._highlightClass"
                :events="item.events"
                @mousedown.stop
                :icon="item.icon"
              >
              </tiny-option>
            </slot>
          </tiny-scrollbar>
          <template
            v-if="!slots.panel && state.emptyText && (!allowCreate || loading || (allowCreate && state.emptyFlag))"
          >
            <!-- tiny 新增 showEmptyImage功能 -->
            <div v-if="loadingText || slots.empty" class="tiny-select-dropdown__empty-wrap">
              <slot name="empty" v-if="slots.empty"></slot>
              <span v-else-if="showEmptyImage" class="tiny-select-dropdown__empty-images"></span>
              <p class="tiny-select-dropdown__empty" v-else>
                {{ state.emptyText }}
              </p>
            </div>
            <div v-else class="tiny-select-dropdown__loading">
              <template v-if="!loading">
                <span v-if="showEmptyImage" class="tiny-select-dropdown__empty-images"></span>
                <span v-else class="tiny-select-dropdown__empty"> {{ state.emptyText }}</span>
              </template>
              <svg v-else class="circular" viewBox="25 25 50 50">
                <circle class="path" cx="50" cy="50" r="24" fill="none" />
              </svg>
            </div>
          </template>
          <!-- tiny 新增 footer插槽 -->
          <slot name="footer"></slot>
        </tiny-select-dropdown>
      </transition>
    </div>
    <div v-if="hoverExpand && !state.isDisplayOnly" class="tiny-base-select__placeholder">
      <input class="tiny-input__inner" disabled />
    </div>
  </div>
</template>

<script lang="ts">
import { renderless, api } from '@opentiny/vue-renderless/base-select/vue'
import { props, setup, directive, defineComponent } from '@opentiny/vue-common'
import TinyTag from '@opentiny/vue-tag'
import TinyInput from '@opentiny/vue-input'
import TinyOption from '@opentiny/vue-option'
import TinyScrollbar from '@opentiny/vue-scrollbar'
import TinySelectDropdown from '@opentiny/vue-select-dropdown'
import TinyButton from '@opentiny/vue-button'
import { Clickoutside } from '@opentiny/vue-directive'
import {
  IconClose,
  IconHalfselect,
  IconCheck,
  IconCheckedSur,
  IconCopy,
  IconDeltaDown,
  IconSearch,
  IconEllipsis,
  IconChevronUp,
  iconAddCircle,
  iconLoadingShadow
} from '@opentiny/vue-icon'
import TinyTooltip from '@opentiny/vue-tooltip'
import FilterBox from '@opentiny/vue-filter-box'
import RecycleScroller from '@opentiny/vue-recycle-scroller'

// tiny 新增
import TinyCheckbox from '@opentiny/vue-checkbox'

import '@opentiny/vue-theme/select/index.less'
import '@opentiny/vue-theme/base-select/index.less'

const getReference = (el, binding, vnode) => {
  const _ref = binding.expression ? binding.value : binding.arg
  const popper = vnode.context.$refs[_ref]

  if (popper) {
    if (Array.isArray(popper)) {
      popper[0].$refs.reference = el
    } else {
      popper.$refs.reference = el
    }
  }
}

export default defineComponent({
  inheritAttrs: false,
  emits: [
    'update:modelValue',
    'change',
    'focus',
    'blur',
    'clear',
    'remove-tag',
    'visible-change',
    'handleDropdownClick',
    'dropdown-click',
    'top-create-click'
  ],
  directives: directive({
    Clickoutside,
    popover: {
      bind(el, binding, vnode) {
        getReference(el, binding, vnode)
      },
      inserted(el, binding, vnode) {
        getReference(el, binding, vnode)
      }
    }
  }),
  components: {
    TinyTag,
    TinyInput,
    TinyOption,
    TinyButton,
    IconClose: IconClose(),
    TinyScrollbar,
    IconCopy: IconCopy(),
    IconAddCircle: iconAddCircle(),
    IconLoadingShadow: iconLoadingShadow(),
    TinySelectDropdown,
    IconHalfselect: IconHalfselect(),
    IconCheck: IconCheck(),
    IconCheckedSur: IconCheckedSur(),
    TinyFilterBox: FilterBox,
    TinyTooltip,
    TinyRecycleScroller: RecycleScroller,
    // tiny 新增，
    IconSearch: IconSearch(),
    IconDeltaDown: IconDeltaDown(), // 默认下拉图标
    TinyCheckbox,
    IconEllipsis: IconEllipsis(),
    IconChevronUp: IconChevronUp()
  },
  props: [
    ...props,
    'id',
    'multiple',
    'name',
    'dataset',
    'readonly',
    'tabindex',
    'dropStyle',
    'valueField',
    'textField',
    'copyable',
    'size',
    'options',
    'showCheck',
    'showAlloption',
    'hideDrop',
    'modelValue',
    'showOverflowTooltip',
    'remote',
    'remoteConfig',
    'placement',
    'loading',
    'disabled',
    'valueKey',
    'clearable',
    'noDataText',
    'filterable',
    'loadingText',
    'noMatchText',
    'popperClass',
    'allowCreate',
    'placeholder',
    'remoteMethod',
    'filterMethod',
    'collapseTags',
    'autocomplete',
    'multipleLimit',
    'reserveKeyword',
    'automaticDropdown',
    'defaultFirstOption',
    'popperAppendToBody',
    'showDropdown',
    'expandTags',
    'delay',
    'cacheOp',
    'isDropInheritWidth',
    'tagSelectable',
    'selectConfig',
    'radioConfig',
    'allowCopy',
    'textSplit',
    'autoClose',
    'queryDebounce',
    'ignoreEnter',
    'dropdownIcon',
    'disabledTooltipContent',
    'hoverExpand',
    'optimization',
    'displayOnly',
    'initQuery',
    'extraQueryParams',
    'shape',
    'label',
    'tip',
    'updateDelay',
    'showTips',
    'popperOptions',
    'trim',
    'topCreate',
    'topCreateText',
    'keepFocus',
    'blank',
    // 以下为 tiny 新增
    'searchable',
    'showEmptyImage',
    'inputBoxType',
    'tagType',
    'clearNoMatchValue',
    'showLimitText',
    'showProportion',
    'clickExpand',
    'maxVisibleRows',
    'showAllTextTag',
    'allText'
  ],
  setup(props, context) {
    return setup({ props, context, renderless, api })
  }
})
</script>
