<template>
  <div class="loyalty-suite-select" @click="toggleDropdown" ref="selectRef">
    <span v-if="label" class="loyalty-suite-select__label">{{ label }}:</span>
    <div class="loyalty-suite-select__wrapper">
      <span class="loyalty-suite-select__selected">{{ selectedLabel }}</span>
      <span class="loyalty-suite-material-icons loyalty-suite-select__icon"
        :class="{ 'loyalty-suite-select__icon_revert': isOpen }">{{ icon }}</span>
    </div>
    <div @click="isOpen = false" v-if="isOpen && isMobile" class="loyalty-suite-select__overlay"></div>
    <transition name="loyalty-suite-select-fade">
      <div v-if="isOpen && options.length" class="loyalty-suite-select__dropdown"
        :class="{ 'loyalty-suite-select__dropdown_mobile': isMobile }">
        <div v-for="option in options" :key="getValue(option)" class="loyalty-suite-select__dropdown-item"
          :class="{ 'loyalty-suite-select__dropdown-item_selected': isSelected(option) }" @click="selectOption(option)">
          <img v-if="getImg(option)" :src="getImg(option)" class="loyalty-suite-select__dropdown-img" />
          <span class="loyalty-suite-select__option">{{ getLabel(option) }}</span>
          <span v-if="getCurrent(option)" class="loyalty-suite-select__dropdown-current">{{ $t('current') }}</span>
        </div>
      </div>
    </transition>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref, computed, onMounted, onUnmounted, watch } from 'vue';

export default defineComponent({
  name: 'Select',
  props: {
    modelValue: {
      type: [String, Number, Object],
      required: false,
    },
    options: {
      type: Array as () => Array<Record<string, any>>,
      required: true,
    },
    emitValue: {
      type: Boolean,
      default: true,
    },
    placeholder: {
      type: String,
      required: false,
    },
    icon: {
      type: String,
      default: 'expand_more',
    },
    label: {
      type: String,
      required: false,
    },
    labelKey: {
      type: String,
      default: 'label',
    },
    valueKey: {
      type: String,
      default: 'value',
    },
    imgKey: {
      type: String,
      default: 'img',
    },
    currentKey: {
      type: Number,
      required: false,
      default: null,
    },
  },
  emits: ['update:modelValue'],
  setup(props, { emit }) {
    const isOpen = ref(false);
    const isMobile = ref(false);
    const selectRef = ref<HTMLElement | null>(null);

    const toggleDropdown = (): void => {
      isOpen.value = !isOpen.value;
    };

    const closeDropdown = (e: MouseEvent): void => {
      if (!selectRef.value?.contains(e.target as Node)) {
        isOpen.value = false;
      }
    };

    const selectOption = (option: any): void => {
      const val = props.emitValue ? getValue(option) : option;
      emit('update:modelValue', val);
      isOpen.value = false;
    };

    const isSelected = (option: any): boolean => {
      const selectedVal = props.modelValue;
      const optionVal = getValue(option);

      return props.emitValue
        ? Number(optionVal) === Number(selectedVal)
        : option === selectedVal;
    };

    const getValue = (opt: any): any => opt?.[props.valueKey];
    const getLabel = (opt: any): string => opt?.[props.labelKey] ?? '';
    const getImg = (opt: any): string | undefined => opt?.[props.imgKey];
    const getCurrent = (opt: any): boolean => {
      return props.currentKey !== null && getValue(opt) === props.currentKey;
    };

    const selectedLabel = computed(() => {
      const selected = props.options.find(opt =>
        props.emitValue
          ? getValue(opt) === props.modelValue
          : opt === props.modelValue
      );
      return selected ? getLabel(selected) : props.placeholder ?? '';
    });

    const checkMobile = (): void => {
      isMobile.value = window.innerWidth <= 768;
    };

    onMounted(() => {
      document.addEventListener('click', closeDropdown);
      window.addEventListener('resize', checkMobile);
      checkMobile();
    });

    watch(isOpen, (val) => {
      if (val && isMobile.value) {
        document.body.classList.add('loyalty-suite-no-scroll');
      } else {
        document.body.classList.remove('loyalty-suite-no-scroll');
      }
    });

    onUnmounted(() => {
      document.removeEventListener('click', closeDropdown);
      window.removeEventListener('resize', checkMobile);
      document.body.classList.remove('loyalty-suite-no-scroll');
    });

    return {
      isOpen,
      isMobile,
      selectRef,
      toggleDropdown,
      selectOption,
      isSelected,
      selectedLabel,
      getLabel,
      getValue,
      getImg,
      getCurrent
    };
  },
});
</script>

<style lang="scss" scoped>
.loyalty-suite-select {
  display: flex;
  align-items: center;
  position: relative;
  width: auto;
  height: 35px;
  max-width: 100%;
  border: 1px solid var(--loyalty-suite-borders-60);
  border-radius: 7px;
  background: var(--loyalty-suite-light);
  transition: 0.3s;

  &:hover {
    cursor: pointer;
    border-color: var(--loyalty-suite-primary);

    .loyalty-suite-select__icon {
      color: var(--loyalty-suite-primary);
    }
  }

  &__overlay {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 9998;
  }

  &__label {
    display: flex;
    justify-content: center;
    align-items: center;
    flex-shrink: 0;
    flex-wrap: nowrap;
    white-space: nowrap;
    user-select: none;
    font-size: 14px;
    font-weight: 400;
    line-height: normal;
    height: 28px;
    border-radius: 5px;
    padding: 0 8px;
    margin-left: 3px;
    background: var(--loyalty-suite-primary);
    color: var(--loyalty-suite-light);
  }

  &__wrapper {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: nowrap;
    max-width: 100%;
    height: 28px;
    padding: 0 12px;
  }

  &__selected {
    display: flex;
    width: 100%;
    flex-wrap: nowrap;
    white-space: nowrap;
    user-select: none;
    font-size: 14px;
    color: var(--loyalty-suite-dark);
    line-height: normal;
    font-weight: 400;
  }

  &__icon {
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 20px;
    margin-left: 10px;
    width: 15px;
    color: var(--loyalty-suite-borders);
    transition: 0.3s;

    &_revert {
      transform: rotate(180deg);
    }
  }

  &__dropdown {
    display: flex;
    flex-direction: column;
    position: absolute;
    background: var(--loyalty-suite-light);
    border: 1px solid var(--loyalty-suite-borders-60);
    border-radius: 7px;
    width: fit-content;
    min-width: 200px;
    margin-top: 38px;
    max-height: 200px;
    top: 0;
    left: 0;
    overflow-y: auto;
    overflow-x: hidden;
    z-index: 1000;
    box-shadow: 0 5px 15px 0 rgba(0, 0, 0, 0.2);

    &::-webkit-scrollbar {
      width: 6px;
    }

    &::-webkit-scrollbar-thumb {
      background-color: var(--loyalty-suite-borders-60);
      border-radius: 10px;
    }

    &::-webkit-scrollbar-button {
      display: none;
      height: 0;
      width: 0;
    }

    &-item {
      display: flex;
      align-items: center;
      width: 100%;
      white-space: normal;
      padding: 10px;
      font-size: 14px;
      user-select: none;
      font-weight: 400;
      color: var(--loyalty-suite-dark);
      line-height: normal;
      border-bottom: 1px solid var(--loyalty-suite-borders-60);

      &:last-child {
        border-bottom: none;
      }

      &:hover {
        cursor: pointer;
        background: var(--loyalty-suite-borders-10);
      }

      &_selected {
        background: var(--loyalty-suite-borders-20);

        &:hover {
          background: var(--loyalty-suite-borders-20);
        }
      }
    }

    &-img {
      display: flex;
      width: 20px;
      height: 20px;
      flex-shrink: 0;
      margin-right: 10px;
      object-fit: cover;
    }

    &-current {
      display: flex;
      justify-content: center;
      align-items: center;
      height: 20px;
      padding: 0 8px;
      color: var(--loyalty-suite-light);
      font-size: 12px;
      font-weight: 700;
      line-height: 1;
      border-radius: 4px;
      background: var(--loyalty-suite-positive);
      margin-left: 10px;
    }

    &_mobile {
      position: fixed;
      min-width: auto;
      margin-top: 0;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      width: calc(100% - 40px);
      max-height: 50vh;
      min-height: 20vh;
      z-index: 9999;
    }
  }

  &__option {
    display: flex;
    flex-shrink: 0;
    white-space: nowrap;
  }
}

.loyalty-suite-select-fade-enter-active,
.loyalty-suite-select-fade-leave-active {
  transition: opacity 0.2s;
}

.loyalty-suite-select-fade-enter-from,
.loyalty-suite-select-fade-leave-to {
  opacity: 0;
}
</style>
