<template>
  <div
    ref="switcher"
    class="nv-switcher"
    :class="[...sizeableClasses, { dark: dark, scrolling: scrolling }]"
  >
    <div
      v-if="scrolling"
      class="nv-switcher__arrow border-r mr-[5px]"
      :style="{ width: `${arrowWidth}px` }"
      @click="prev"
    >
      <NvIcon class="nv-switcher__arrow-icon" :icon="prevIcon" />
    </div>
    <ul ref="list" class="nv-switcher__list">
      <div ref="slider" class="nv-switcher__slider"></div>
      <li
        v-for="(item, i) in items"
        :key="i"
        ref="item"
        class="nv-switcher__item"
        @click="indexChanged(i)"
      >
        <div
          class="nv-switcher__link"
          :class="[
            item.customClass ? item.customClass : '',
            customClass,
            { active: index === i },
          ]"
          :style="{
            minWidth: `${minWidth}px`,
          }"
        >
          <NvIcon
            v-if="item.icon"
            :icon="item.icon"
            class="nv-switcher__icon"
          />
          <div
            class="nv-switcher__title"
            :class="{
              'no-wrap': noWrap,
              icon: item.icon,
              'icon-right': item.iconRight,
            }"
          >
            {{ itemText !== "" ? item[itemText] : item }}
          </div>
          <NvIcon
            v-if="item.iconRight"
            :icon="item.iconRight"
            class="nv-switcher__icon"
          />
        </div>
        <div v-if="i < items.length - 1" class="nv-switcher__divider"></div>
      </li>
    </ul>
    <div
      v-if="scrolling"
      class="nv-switcher__arrow border-l ml-[5px]"
      :style="{ width: `${arrowWidth}px` }"
      @click="next"
    >
      <NvIcon class="nv-switcher__arrow-icon" :icon="nextIcon" />
    </div>
  </div>
</template>

<script>
import useSize from "../../composables/sizeable";
import { nextTick, onMounted, onUnmounted, ref, watch } from "vue";

export default {
  name: "NvSwitcher",

  props: {
    customClass: { type: String, default: "" },
    dark: Boolean,
    items: {
      type: Array,
      default: () => [false, true],
    },
    itemText: { type: String, default: "" },
    itemValue: { type: String, default: "" },
    nextIcon: { type: String, default: "nvi-chevron-double-right" },
    minWidth: { type: Number, default: 100 },
    modelValue: {
      type: [Boolean, Number, String],
      default: null,
    },
    noWrap: Boolean,
    prevIcon: { type: String, default: "nvi-chevron-double-left" },
    size: { type: String, default: "md" },
  },

  setup(props, { emit }) {
    const { sizeableClasses } = useSize(props);
    const lastIndex = ref(0);
    const index = ref(0);
    const scrolling = ref(false);
    const arrowWidth = 35;

    const item = ref([]);
    const list = ref(null);
    const slider = ref(null);
    const switcher = ref(null);

    const initIndex = () => {
      index.value = props.items.findIndex(
        (i) => (props.itemValue ? i[props.itemValue] : i) === props.modelValue
      );
      if (index.value === -1) index.value = 0;
    };

    const indexChanged = (i) => {
      index.value = i;
      setSliderPosition();
      const result =
        props.itemValue === ""
          ? props.items[i]
          : props.items[i][props.itemValue];
      emit("update:modelValue", result);
    };

    const setSliderSpeed = () => {
      const steps = Math.abs(lastIndex.value - index.value);
      lastIndex.value = index.value;
      slider.value.style.transition = 0.1 * steps + "s";
    };

    const getScrolling = () => {
      scrolling.value = false;
      nextTick(() => {
        scrolling.value = list.value.offsetWidth < list.value.scrollWidth - 10; // 10px запас, чтобы не дергалась лишний раз при ресайзе
        setSliderPosition();
      });
    };

    const next = () => {
      const items = list.value.querySelectorAll(".nv-switcher__item");
      const itemsPositions = [];

      items.forEach((i) => {
        itemsPositions.push(i.offsetLeft + i.clientWidth - 1); // 1px - divider
      });
      const currentPosition =
        Math.ceil(list.value.scrollLeft) + list.value.clientWidth + 10;
      let nextPosition = itemsPositions.find((ip) => ip > currentPosition);

      if (nextPosition === undefined) return;
      nextPosition = nextPosition - list.value.clientWidth;
      list.value.scrollTo({
        left: nextPosition,
        top: 0,
        behavior: "smooth",
      });
    };

    const prev = () => {
      const items = list.value.querySelectorAll(".nv-switcher__item");
      const itemsPositions = [];

      items.forEach((i) => {
        itemsPositions.push(i.offsetLeft);
      });
      const currentPosition = Math.floor(list.value.scrollLeft) - 10;
      const nextPosition = itemsPositions
        .reverse()
        .find((ip) => ip < currentPosition);

      if (nextPosition === undefined) return;
      list.value.scrollTo({
        left: nextPosition,
        top: 0,
        behavior: "smooth",
      });
    };

    const setSliderPosition = () => {
      setSliderSpeed();
      setTimeout(() => {
        const elements = switcher.value.querySelectorAll(".nv-switcher__item");
        slider.value.style.width = `${elements[index.value].clientWidth + 4}px`;
        slider.value.style.left = `${elements[index.value].offsetLeft - 2}px`;
      }, 100);
    };

    watch(
      () => props.modelValue,
      () => {
        initIndex();
      }
    );

    onMounted(() => {
      initIndex();
      getScrolling();
      window.addEventListener("resize", getScrolling);
    });

    onUnmounted(() => {
      window.removeEventListener("resize", getScrolling);
    });

    return {
      arrowWidth,
      index,
      indexChanged,
      item,
      list,
      next,
      prev,
      scrolling,
      sizeableClasses,
      slider,
      switcher,
    };
  },
};
</script>

<style scoped lang="scss">
.nv-switcher {
  @apply bg-gray-100 border-gray-100 border-4 flex relative rounded-md px-[2px] max-w-full;

  &__arrow {
    @apply border-gray-300 cursor-pointer flex justify-center items-center shrink-0 text-subline hover:text-black;
  }

  &__item {
    @apply flex grow;
  }

  &__link {
    @apply cursor-pointer flex grow justify-center items-center py-2 px-5 z-10;
  }

  &__list {
    @apply flex grow list-none m-0 p-0 relative overflow-x-auto overflow-y-hidden;
  }

  &__slider {
    @apply absolute bg-white h-full top-0 rounded z-10;
  }

  &__title.no-wrap {
    white-space: nowrap;
  }

  &__divider {
    @apply my-2 border-l border-black/10;
  }

  &.dark {
    @apply bg-black border-black text-white;

    .nv-switcher__arrow {
      @apply border-gray-800 text-subline hover:text-white;
    }

    .nv-switcher__slider {
      @apply bg-[#3c3c3c];
    }

    .nv-switcher__divider {
      @apply border-white/30;
    }
  }
}

.nv-switcher__list::-webkit-scrollbar {
  @apply h-0 w-0 bg-transparent;
}
</style>
