<template>
  <div
    class="select"
    ref="selectRef"
    :class="[variant]"
    @keydown="handleFocusedSelectKeydown"
  >
    <div
      class="valueContainer text-textDarkest"
      :data-testid="name ? `select:${name}` : 'select'"
      @click="activateDropdown"
    >
      <div class="text-muted" v-if="isValueEmpty">{{ placeholder }}</div>

      <slot
        v-if="!isValueEmpty && !multiple && customRender"
        :option="getOption(localValue)"
      />
      <template v-else>
        {{ getOptionLabel(localValue) }}
      </template>

      <div v-if="!isValueEmpty && multiple" class="valueMulti text-textDarkest">
        <div
          class="my-1 mx-1 flex items-center"
          v-for="optionValue in localValue"
          :key="optionValue"
        >
          <slot
            v-if="customRender"
            :option="getOption(optionValue)"
            :value="optionValue"
            :remove="removeOptionValue"
          />
          <div v-else class="valueMultiItem text-textDarkest" :style="getOptionColor(optionValue) ? `background-color: #${getOptionColor(optionValue)}; color: #fff` : ''">
            <div class="valueMultiItemLabel">
              {{ getOptionLabel(optionValue) }}
            </div>
            <div
              @click="removeOptionValue(optionValue)"
              class="valueMultiItemClose"
            >
              <svg class="icon" viewBox="0 0 24 24">
                <path
                  d="M16.192 6.344L11.949 10.586 7.707 6.344 6.293 7.758 10.535 12 6.293 16.242 7.707 17.656 11.949 13.414 16.192 17.656 17.606 16.242 13.364 12 17.606 7.758z"
                />
              </svg>
            </div>
          </div>
        </div>

        <div class="addMore m-1">
          <svg
            class="icon"
            viewBox="0 0 24 24"
            focusable="false"
            role="presentation"
          >
            <path
              d="M13 11V3.993A.997.997 0 0 0 12 3c-.556 0-1 .445-1 .993V11H3.993A.997.997 0 0 0 3 12c0 .557.445 1 .993 1H11v7.007c0 .548.448.993 1 .993.556 0 1-.445 1-.993V13h7.007A.997.997 0 0 0 21 12c0-.556-.445-1-.993-1H13z"
              fill="currentColor"
              fill-rule="evenodd"
            ></path>
          </svg>
          <div class="font-medium">{{ addMoreText }}</div>
        </div>
      </div>

      <icon
        v-if="(!multiple || isValueEmpty) && variant !== 'empty'"
        class="ml-auto mr-1"
        name="chevron_down"
      ></icon>
    </div>

    <Dropdown
      v-if="isDropdownOpen"
      ref="dropdownRef"
      isValueEmpty
      :dropdownWidth="dropdownWidth"
      :searchable="searchable"
      :searchValue="searchValue"
      :value="localValue"
      :deactivateDropdown="deactivateDropdown"
      :options="options"
      :multiple="multiple"
      :item-key="itemKey"
      :item-text="itemText"
      :withClearValue="withClearValue"
      @change="handleChange"
      @searchValueChange="handleSearchValueChange"
    >
      <template #option="{ option }">
        <slot v-if="customRenderOption" name="option" :option="option" />
        <slot v-else :option="option" />
      </template>
    </Dropdown>
  </div>
</template>

<script>
import { Component, Model, Prop, Ref } from 'vue-property-decorator';
import Vue from 'vue';
import Icon from '../icon/Icon.vue';
import Dropdown from './Dropdown.vue';
import { useOutsideClick } from './useOutsideClick';

const { bind, unbind } = useOutsideClick();

export default @Component({
  name: 'itfAirSelect',
  components: { Dropdown, Icon },
})
class itfAirSelect extends Vue {
  @Model('input', { type: [Array, String, Number], default: undefined }) value;

  @Prop({ type: Number, default: undefined }) dropdownWidth;

  @Prop({ type: String, default: 'normal' }) variant;

  @Prop({ type: String, default: 'value' }) itemKey;
  @Prop({ type: String, default: 'label' }) itemText;
  @Prop({ type: String, default: 'color' }) itemColor;

  @Prop({ type: String, default: undefined }) name;

  @Prop({ type: Boolean, default: false }) searchable;

  @Prop({ type: [String, Array, Number], default: undefined }) defaultValue;

  @Prop({ type: String, default: 'Select' }) placeholder;

  @Prop({ type: Boolean, default: false }) invalid;

  @Prop({ type: Array, required: true }) options;

  @Prop({ type: Boolean, default: false }) multiple;

  @Prop({ type: Boolean, default: false }) withClearValue;

  @Prop({ type: Boolean, default: false }) customRender;
  @Prop({ type: Boolean, default: false }) customRenderOption;
  // eslint-disable-next-line object-shorthand
  @Prop({ type: String, default: function() { return this.$t('components.addMore'); } }) addMoreText;

  @Ref('selectRef') selectRef;

  @Ref('dropdownRef') dropdownRef;

  isDropdownOpen = false;

  searchValue = '';

  data() {
    return {
      stateValue: this.defaultValue || (this.multiple ? [] : null),
    };
  }

  getOption(optionValue) {
    return this.options.find((option) => option[this.itemKey] === optionValue);
  }

  getOptionLabel(optionValue) {
    return (this.getOption(optionValue) || { [this.itemText]: '' })[this.itemText];
  }

  getOptionColor(optionValue) {
    return (this.getOption(optionValue) || { [this.itemColor]: '' })[this.itemColor];
  }

  get isControlled() {
    return this.value !== undefined;
  }

  get localValue() {
    return this.isControlled ? this.value : this.stateValue;
  }

  preserveValueType(newValue) {
    const areOptionValuesNumbers = this.options.some(
      (option) => typeof option[this.itemKey] === 'number',
    );
    if (areOptionValuesNumbers) {
      if (this.multiple) {
        return (newValue).map(Number);
      }
      if (newValue) {
        return Number(newValue);
      }
    }
    return newValue;
  }

  handleChange(newValue) {
    if (!this.isControlled) {
      this.stateValue = this.preserveValueType(newValue);
    }
    this.$emit('input', this.preserveValueType(newValue));
  }

  removeOptionValue(optionValue) {
    this.handleChange(this.localValue.filter((val) => val !== optionValue));
  }

  get isValueEmpty() {
    return this.multiple ? !this.localValue.length : !this.getOption(this.localValue);
  }

  handleFocusedSelectKeydown(event) {
    if (this.isDropdownOpen) return;
    if (event.keyCode === 13) {
      event.preventDefault();
    }
    if (event.keyCode !== 27 && event.keyCode !== 9 && !event.shiftKey) {
      this.isDropdownOpen = true;
    }
  }

  async deactivateDropdown() {
    this.isDropdownOpen = false;
    this.searchValue = '';
    await this.$nextTick();
    this.selectRef && this.selectRef.focus();
  }

  async activateDropdown() {
    this.isDropdownOpen = true;
    await this.$nextTick();
    this.selectRef && this.selectRef.blur();
    // eslint-disable-next-line
    this.searchable && this.dropdownRef && this.dropdownRef.$refs.inputRef.focus()
  }

  handleSearchValueChange(newValue) {
    this.searchValue = newValue;
  }

  mounted () {
    bind(this.selectRef, this.deactivateDropdown);
  }

  beforeDestroy () {
    unbind();
  }
}
</script>
