<template>
  <div
    :class="[
      { unselected: selected && !selected.value },
      { disabled: disabled },
      'app-select',
      size,
    ]"
    :style="{ maxWidth: `${width}px` }"
  >
    <div
      :class="`app-select-input${validated ? ' error-validate' : ''}`"
      :data-id="id"
      :title="(selected && selected.title) || 'Выберите значение'"
    >
      {{ (selected && selected.title) || "Выберите значение" }}
      <div class="app-select-input--arrow">
        <IconBase
          icon-name="arrow-down"
          :width="13"
          :height="7"
          :viewBox="'0 0 13 7'"
        >
          <IconArrowDown />
        </IconBase>
      </div>
    </div>
    <div v-if="validated" class="error-text">{{ error }}</div>
    <transition :name="transition">
      <div
        :class="`app-select-options ${position}`"
        :style="{ width: `${widthOptions}px` }"
        v-if="isShowOptions"
      >
        <AppInput
          v-if="placeholderSearch.length"
          :placeholder="placeholderSearch"
          :value="search_options"
          @input="changeSearch"
          focus
          search
          select
        />
        <AppScrollbar
          :changeContent="filteredOptions().length"
          :height="heightScroll"
          select
        >
          <div
            v-for="option in filteredOptions()"
            :class="[
              'app-select-option',
              { disabled: option.disabled },
              { html: !!option.html },
            ]"
            @click="changeOption(option)"
            :key="option.value"
            :title="option.title"
            v-html="option.html || option.title"
          ></div>
          <div
            class="app-select-option--no"
            v-if="isEmpty"
            v-html="empty"
          ></div>
        </AppScrollbar>
      </div>
    </transition>
  </div>
  <AppNotification type="ERROR" :text="error_used" v-if="isShowNotification" />
</template>

<script>
import { IconBase, IconArrowDown } from "../Icons/index";
import { AppInput, AppScrollbar, AppNotification } from "./index";

export default {
  name: "app-select",
  props: {
    options: {
      type: Array,
      default: () => [],
    },
    used: {
      type: Array,
      default: () => [],
    },
    selected: {
      type: Object,
      default: () => {},
    },
    placeholderSearch: {
      type: String,
      default: "",
    },
    width: { type: Number },
    widthOptions: { type: Number },
    heightScroll: {
      type: Number,
      default: 168,
    },
    validated: {
      type: Boolean,
      default: false,
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    addition: {
      type: Boolean,
      default: false,
    },
    error: {
      type: String,
      default: "Поле не заполнено",
    },
    error_used: {
      type: String,
      default: "Нельзя выбрать это значение",
    },
    empty: {
      type: String,
      default: "<span>Список пуст</span>",
    },
    size: {
      type: String,
      default: "normal",
      validator: function (value) {
        return ["small", "normal"].includes(value);
      },
    },
  },
  emits: ["select"],
  components: {
    IconBase,
    IconArrowDown,
    AppInput,
    AppScrollbar,
    AppNotification,
  },
  data() {
    return {
      id: null,
      isShowOptions: false,
      isShowNotification: false,
      search_options: "",
      position: "bottom",
      transition: "dropdown_down",
    };
  },
  methods: {
    changeOption(option) {
      if (this.used.find((u) => u === option.value)) {
        this.isShowNotification = true;
        return;
      }
      this.$emit("select", option);
      this.isShowOptions = false;
      this.search_options = "";
    },
    changeSearch(event) {
      if (!!event && !!event.target) {
        this.search_options = event.target.value;
      }
    },
    filteredOptions() {
      let options = this.options.filter((item) =>
        item.title.toLowerCase().includes(this.search_options.toLowerCase())
      );
      if (this.addition && this.search_options.length) {
        options.unshift({
          value: this.search_options,
          title: this.search_options,
        });
      }
      return options;
    },
    hideOptions(e) {
      if (e.target.dataset.id === this.id) {
        const select = document.querySelector(
          `[data-id='${e.target.dataset.id}']`
        );
        const top_select =
          select.getBoundingClientRect().top + document.body.scrollTop;
        const windowInnerHeight = window.innerHeight;

        let height_options_content = this.filteredOptions().length * 32 + 16;
        let height_options =
          this.heightScroll >= height_options_content
            ? height_options_content
            : this.heightScroll;
        this.position =
          top_select + height_options + 80 > windowInnerHeight
            ? "top"
            : "bottom";
        this.transition =
          top_select + height_options + 80 > windowInnerHeight
            ? "dropdown_up"
            : "dropdown_down";
        this.isShowOptions = !this.isShowOptions;
      } else if (
        e.target.tagName !== "INPUT" &&
        e.target.className !== "select"
      ) {
        this.isShowOptions = false;
      }
      this.search_options = "";
    },
  },
  mounted() {
    this.id = `app-select-input_${Math.random()}`;
    document.addEventListener("click", this.hideOptions, true);
  },
  beforeUnmount() {
    document.removeEventListener("click", this.hideOptions, true);
  },
  computed: {
    isEmpty() {
      return (
        !this.filteredOptions().length ||
        (this.filteredOptions().length === 1 &&
          this.filteredOptions()[0].title === "")
      );
    },
  },
  watch: {
    isShowNotification(show) {
      if (show) {
        setTimeout(() => (this.isShowNotification = false), 3000);
      }
    },
  },
};
</script>

<style lang="sass" scoped>
@import "../../assets/_vars"
@import "../../assets/_transition"

.app-select
  position: relative
  min-height: 40px
  &.disabled
    .app-select-input
      pointer-events: none
      background-color: $gray4
      color: $gray1
  &.unselected
    .app-select-input
      color: $gray1
  &.small
    min-height: 32px
    .app-select-input
      padding: 8px 40px 8px 16px
      height: 32px
  &-input
    position: relative
    padding: 12px 40px 12px 16px
    width: 100%
    // min-width: 168px
    height: 40px
    background: white
    border: 1px solid $gray5
    border-radius: 4px
    cursor: pointer
    user-select: none
    white-space: nowrap
    overflow: hidden
    text-overflow: ellipsis
    line-height: 1
    &--arrow
      display: flex
      justify-content: center
      align-items: center
      position: absolute
      right: 0
      top: 0
      height: 100%
      width: 40px
      pointer-events: none
    &.error-validate
      border-color: $red1
  &-options
    position: absolute
    left: 0
    z-index: 1
    padding: 0 0 8px
    max-height: 216px
    overflow: hidden
    width: 100%
    border-radius: 4px
    background: white
    box-shadow: 0px 3px 14px rgba(55, 71, 79, 0.3)
    color: $gray3
    &.bottom
      top: 100%
      margin-top: 9px
    &.top
      bottom: 100%
      margin-bottom: 9px
    .input input
      border-radius: 0
      border: none
      border-bottom: 1px solid $gray5
  &-option
    padding: 8px 16px
    width: 100%
    height: 32px
    transition: background 0.3s ease 0s
    white-space: nowrap
    overflow: hidden
    text-overflow: ellipsis
    cursor: pointer
    &.disabled
      pointer-events: none
      color: $gray1
    &.html
      min-height: 32px
      height: auto
      white-space: normal
    &--no
      padding: 8px 16px 0
    &:hover
      background: #E3F2FD
  .error-text
    padding: 4px 0 0
    font-size: 12px
    line-height: 16px
    color: $red1
</style>
