<template>
  <div
    :class="containerClass"
    :style="style"
    class="vc-tree-select"
  >
    <div class="vc-tree-select__label-wrap">
      <label
        v-if="label || labelIcon"
        class="vc-tree-select__label"
      >
        <span
          v-if="labelIcon"
          class="vc-tree-select__label-icon-wrap"
        >
          <i
            :class="labelIcon"
            class="icon-lg vc-tree-select__label-icon text-icons"
          />
        </span>
        <span
          v-if="label"
          class="vc-tree-select__label-text"
        >
          {{ label }}
          <span
            v-if="required"
            class="vc-tree-select__label-required-icon"
          >
            *
          </span>
        </span>
        <VcPopover
          v-if="infoText || $slots['info-text']"
          :popover-width="infoTooltipWidth"
          arrow-position="bottom-center"
        >
          <template #reference>
            <span class="vc-input__label-info px-1 flex items-center">
              <i class="vc-icon-info icon-base" />
            </span>
          </template>
          <div
            class="label-info-text p-2 text-xs"
          >
            <slot name="info-text">
              {{ infoText }}
            </slot>
          </div>
        </VcPopover>
      </label>
    </div>
    <VcPopover
      :click-outside-handler="closeDropdown"
      :open="open"
      popover-class="vc-tree-select__dropdown"
      popover-width="100%"
      max-width="100%"
      trigger="manual"
      arrow-position="top-right"
      class="vc-tree-select__dropdown-wrapper"
    >
      <template #reference>
        <div
          :class="[
            ...inputClasses,
            {
              'is-prefix-icon': prefixIcon,
              'is-error': !!error,
              'is-disabled': disabled
            }
          ]"
          class="vc-tree-select__container"
          @click="onWrapperClick"
        >
          <div
            v-if="prefixIcon"
            class="vc-tree-select__prefix-icon"
          >
            <i
              :class="prefixClasses"
              :style="prefixStyle"
            />
          </div>
          <div
            class="vc-tree-select__content"
          >
            <div class="vc-tree-select__tags flex flex-wrap">
              <VcDelimitedList
                :list="selectedModel"
                :limit="tagsLimit"
                max-width="180"
                separator=""
              >
                <template #list-item="{item}">
                  <VcTag
                    :label="item?.label"
                    :color="tagColor"
                    :max-content="tagMaxContent"
                    :borderless="tagBorderless"
                    :disabled="disabled"
                    closable
                    @on-close="onRemoveTag(item)"
                  />
                </template>
                <template #reference="{listLength}">
                  <VcTag
                    :label="`+ ${listLength}`"
                    :borderless="tagBorderless"
                  />
                </template>
                <template #other-content="{list}">
                  <div class="w-full py-3 px-2">
                    <div
                      v-for="(item, index) in list"
                      :key="index"
                      class="flex items-center justify-start m-1"
                    >
                      <VcTag
                        :label="item.label"
                        :icon="item.icon"
                        :max-content="tagMaxContent"
                        :borderless="tagBorderless"
                        :disabled="disabled"
                        closable
                        @on-close="onRemoveTag(item)"
                      />
                    </div>
                  </div>
                </template>
              </VcDelimitedList>
            </div>
          </div>
          <div
            class="vc-tree-select__suffix-icon"
          >
            <i
              class="vc-icon-folders text-icons icon-lg"
            />
          </div>
        </div>
      </template>
      <div
        v-if="loading"
        ref="dropdown"
        class="vc-tree-select__dropdown-content h-full"
      >
        <div class="vc-tree-select__dropdown-tree-content">
          <VcTree
            v-if="options.length"
            ref="treNode"
            v-model:expandedKeys="expandedKeys"
            :config="config"
            :options="options"
            :scroll-height="scrollHeight"
            :default-checked-keys="checkedKeys"
            :empty-text="emptyTextMessage"
            @update:selectedKeys="onSelectedKeys"
          >
            <template
              v-if="$slots['option-label']"
              #node-label="data"
            >
              <slot
                name="option-label"
                :node="data.node"
              />
            </template>
          </VcTree>
          <div
            v-else
            class="vc-tree-select__empty-text"
          >
            {{ emptyTextMessage }}
          </div>
        </div>
      </div>
    </VcPopover>
    <div class="vc-tree-select__error-wrapper">
      <span class="vc-tree-select__error-wrapper--text">
        {{ error }}
      </span>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, PropType } from 'vue'
import { VcTagColorType } from '@/components/VcTag/VcTag.types'
import baseInputMixin from '@/mixins/baseInput.mixin'
import VcTag from '@/components/VcTag/VcTag.vue'
import VcPopover from '@/components/VcPopover/VcPopover.vue'
import VcTree from '@/components/VcTree/VcTree.vue'
import { VcTreeActionKeys, VcTreeConfig, VcTreeNodeType } from '@/components/VcTree/VcTree.types'
import VcDelimitedList from '@/components/VcDelimitedList/VcDelimitedList.vue'

const CLASS_FOR_COLOR = 'vc-tree-select--'
const DEFAULT_CONFIG = {
  valueKey: 'id',
  labelKey: 'label',
  iconKey: 'icon',
  childrenKey: 'children'
}

export default defineComponent({
  name: 'VcTreeSelect',
  components: { VcDelimitedList, VcTree, VcPopover, VcTag },
  mixins: [baseInputMixin],
  props: {
    modelValue: {
      type: Array as PropType<VcTreeNodeType[]>,
      default: undefined
    },
    class: {
      type: String,
      default: ''
    },
    style: {
      type: [String, Object],
      default: null
    },
    tagColor: {
      type: String as PropType<VcTagColorType>,
      default: 'primary'
    },
    tagBorderless: {
      type: Boolean,
      default: false
    },
    config: {
      type: Object as PropType<VcTreeConfig>,
      default: () => ({ ...DEFAULT_CONFIG })
    },
    options: {
      type: Array as PropType<VcTreeNodeType[]>,
      default: () => []
    },
    returnedValue: {
      type: String,
      default: ''
    },
    loading: {
      type: Boolean,
      default: true
    },
    emptyText: {
      type: String,
      default: ''
    },
    tagsLimit: {
      type: Number,
      default: 3
    },
    scrollHeight: {
      type: [String, Number],
      default: 252
    }
  },
  emits: ['update:modelValue', 'on-change'],
  data () {
    return {
      colorClass: CLASS_FOR_COLOR,
      focused: false,
      tagMaxContent: '160',
      open: false,
      localData: [] as VcTreeNodeType[],
      expandedKeys: {} as VcTreeActionKeys[]
    }
  },
  computed: {
    nodeKey (): string | number {
      return this.config?.valueKey || DEFAULT_CONFIG.valueKey
    },
    selectedModel: {
      get (): VcTreeNodeType[] {
        if (this.modelValue === undefined) {
          return this.localData
        }
        return Array.isArray(this.modelValue) ? this.modelValue : []
      },
      set (val: VcTreeNodeType[]) {
        if (this.modelValue === undefined) {
          this.localData = val
        } else {
          this.emitData(val)
        }
      }
    },
    checkedKeys () {
      return this.selectedModel.map((item: VcTreeNodeType) => item[this.nodeKey])
    },
    inputClasses (): (string)[] {
      const colorClass = this.color ? (this.colorClass + this.color) : ''
      return [
        colorClass
      ]
    },
    containerClass () {
      return [this.class, {
        'vc-tree-select__wrap--filled': !!(this.modelValue && this.modelValue.length),
        'vc-tree-select__wrap--focus': this.open,
        'vc-tree-select__wrap--error': !!this.error,
        'vc-tree-select__wrap--disabled': this.disabled
      }]
    },
    emptyTextMessage () {
      return this.emptyText ? this.emptyText : this.$tVU.t('general.no.data')
    }
  },
  methods: {
    emitData (val: VcTreeNodeType[]): void {
      if (this.returnedValue) {
        const _res = val.map((item: VcTreeNodeType) => item[this.returnedValue])
        this.$emit('on-change', _res)
      } else {
        this.$emit('on-change', val)
      }
      this.$emit('update:modelValue', val)
    },
    onWrapperClick (): void {
      if (!this.disabled) {
        this.open = true
      }
    },
    closeDropdown (): void {
      this.open = false
    },
    onRemoveTag (data: VcTreeNodeType) {
      this.selectedModel = this.selectedModel.filter((item: VcTreeNodeType) => item[this.nodeKey] !== data[this.nodeKey])
      this.$nextTick(() => {
        if (this.$refs.treNode) {
          // eslint-disable-next-line @typescript-eslint/no-explicit-any
          (this.$refs.treNode as any).initData()
        }
      })
    },
    onSelectedKeys (data: VcTreeNodeType[]) {
      this.selectedModel = data
    }
  }
})
</script>

<style lang="scss" scoped>
@import '../../assets/sass/main/mixins';
.vc-tree-select {
  &__wrap {
    @apply w-full;
  }
  @include labelCustomInput;
  @include errorContainer;

  &__prefix-icon {
    @apply flex-shrink-0 flex items-center justify-center px-1 h-full;
    flex: 0 0 1rem;
    .vc-input-icon-color--active {
      @apply text-active-elements;
    }
    .vc-input-icon-color--primary {
      @apply text-primary-actions;
    }
    .vc-input-color--secondary {
      @apply text-secondary-actions;
    }
    .vc-input-icon-color--destructive {
      @apply text-destructive-actions;
    }
  }
  &__suffix-icon {
    @apply flex-shrink-0 flex items-center justify-center px-1;
    flex: 0 0 2rem;
    i {
      cursor: inherit;
      transition: all 0.3s ease;
      &:hover {
        @apply text-icons;
      }
    }
  }
  &__container {
    @apply
    min-h-8
    pl-3
    w-full
    max-w-full
    flex items-center justify-between text-sm rounded border border-field-borders outline-none overflow-hidden cursor-pointer;
    &.is-prefix-icon {
      @apply pl-0;
    }
    &:hover:not(.is-disabled) {
      @apply shadow-focus-outer;
    }
    &.vc-tree-select--active {
      &:hover:not(.is-disabled) {
        @apply shadow-focus-outer;
      }
      &:focus:not(.is-disabled):not(.is-error) {
        @apply border-active-elements--focus;
      }
    }
    &.vc-tree-select--primary {
      &:hover:not(.is-disabled) {
        @apply shadow-focus-outer-primary;
      }
      &:focus:not(.is-disabled):not(.is-error) {
        @apply border-primary-actions--focus;
      }
    }
    &.vc-tree-select--secondary {
      &:hover:not(.is-disabled) {
        @apply shadow-focus-outer-secondary;
      }
    }
    &.vc-tree-select--destructive {
      &:hover:not(.is-disabled) {
        @apply shadow-focus-outer-destructive;
      }
    }
  }
  &__tags {
    @apply flex-grow;
    .vc-tree-select__tag-item {
      @apply mr-1;
    }
  }
  &__wrap {
    &--focus:not(&--disabled):not(&--error) {
      .vc-tree-select__container {
        @apply border-primary-actions--focus;
        &.vc-tree-select--active {
          &:not(.is-error) {
            @apply border-active-elements--focus;
          }
        }
        &.vc-tree-select--primary {
          &:not(.is-error) {
            @apply border-primary-actions--focus;
          }
        }
        &.vc-tree-select--secondary {
          &:not(.is-error) {
            @apply border-secondary-actions--focus;
          }
        }
        &.vc-tree-select--destructive {
          &:not(.is-error) {
            @apply border-destructive-actions--focus;
          }
        }
      }
    }
    &--error {
      .vc-tree-select__container {
        @apply border-error;
      }
    }
    &--disabled {
      .vc-tree-select__container, input {
        @apply bg-default-bg;
        &:hover {
          @apply cursor-not-allowed shadow-none;
        }
      }
    }
  }
  &__content {
    @apply flex-grow flex-wrap;
    overflow: hidden;
    flex: 1 0 2rem;
  }
  &__empty-text {
    @apply text-center text-inactive-elements pt-2 items-center;
  }
  &__dropdown-content {
    @apply overflow-hidden py-3 px-1;
  }
}
</style>
<style lang="scss">
[dir='rtl'] {
  .vc-tree-select {
    &__container {
      @apply pr-3;
      &.is-prefix-icon {
        @apply pr-0;
      }
    }
    &__tags {
      .vc-tag-input__tag-item {
        @apply mr-0 ml-1;
      }
    }
  }
}
</style>
