<template>
  <div
    v-if="!hidden"
    class="nv-list-item"
    :class="[
      rounded,
      {
        absoluteClass: absolute,
        active: active && !parentNoAction,
        dark: parentDark,
        disabled: disabled,
        mini: mini,
        opened: computedOpened,
        submenu: submenu,
      },
    ]"
  >
    <hr v-if="divider" class="nv-list-item__divider" />
    <component
      v-if="hasTitle"
      :is="to ? (to.includes('http') ? 'a' : 'router-link') : 'div'"
      :to="to || '#'"
      :href="to || '#'"
      :target="target"
      class="nv-list-item__title"
      :class="[
        customClass,
        parentCustomClass,
        rounded,
        {
          'rounded-b-none': !absolute && submenu && computedOpened,
        },
      ]"
      v-tippy="{
        content: mini ? tooltip : '',
        placement: 'right',
        delay: 200,
      }"
      :style="{ 'padding-left': `${20 * (1 + level)}px` }"
      @click="click"
    >
      <NvIcon v-if="icon" :icon="icon" class="nv-list-item__icon" />
      <div v-if="!mini" class="nv-list-item__title-content">
        <div
          class="nv-list-item__title-text"
          :class="{ 'ml-4': icon, 'mr-4': iconRight }"
        >
          <div v-if="title">{{ title }}</div>
          <slot name="default" />
        </div>
        <NvIcon
          v-if="iconRight"
          :icon="iconRight"
          class="nv-list-item__icon-right"
        />
        <div v-if="hotkey" class="nv-list-item__hotkey">
          {{ hotkey }}
        </div>
        <NvIcon
          v-if="submenu"
          icon="nvi-chevron-right"
          class="nv-list-item__title-arrow"
        />
      </div>
    </component>
    <div
      ref="content"
      v-show="hasContent && (computedOpened || !submenu) && (!mini || absolute)"
      class="nv-list-item__content"
      :class="[
        absolute ? parentRounded : rounded + (submenu ? ' rounded-t-none' : ''),
        { openToLeft: openToLeft },
      ]"
    >
      <slot name="content">
        <NvList
          v-if="list"
          :absolute="list.absolute"
          :accordeon="list.accordeon"
          :customClass="list.customClass"
          :dark="list.dark"
          :icon="list.icon"
          :items="list.items"
          :minWidth="list.minWidth"
          :multiple="list.multiple"
          :noAction="list.noAction"
          :size="list.size"
          :title="list.title"
        />
      </slot>
    </div>
  </div>
</template>

<script>
import { computed } from "vue";

export default {
  name: "NvListItem",

  props: {
    customClass: { type: String, default: undefined },
    disabled: Boolean,
    divider: Boolean,
    hidden: Boolean,
    hotkey: { type: String, default: "" },
    icon: { type: String, default: "" },
    iconRight: { type: String, default: "" },
    list: { type: Object, default: undefined },
    submenu: Boolean,
    target: { type: String, default: "" },
    title: { type: String, default: "" },
    to: { type: String, default: "" },
    tooltip: { type: String, default: "" },
  },

  inject: {
    level: { default: 0 },
    mini: { default: false },
    parentAbsolute: { default: false },
    parentAccordeon: { default: false },
    parentActiveItems: { default: [] },
    parentCustomClass: { default: "" },
    parentDark: { default: false },
    parentMultiple: { default: false },
    parentNoAction: { default: false },
    parentOpenItems: { default: [] },
    parentRounded: { default: "" },
    parentItemRounded: { default: undefined },
  },

  data: () => {
    return {
      absolute: false,
      activeItems: [],
      computedOpened: false,
      id: "",
      openToLeft: false,
      openItems: [],
      parent: null,
    };
  },

  provide() {
    return {
      level: computed(() =>
        (this.absolute && this.submenu) || !this.hasTitle ? 0 : this.level + 1
      ),
      mini: false,
      parentCustomClass: this.customClass ?? this.parentCustomClass,
      parentItemRounded: computed(() => {
        let rounded = this.rounded;
        if (this.submenu) rounded += " rounded-t-none";
        return this.absolute ? this.parentRounded : rounded;
      }),
    };
  },

  computed: {
    active() {
      return this.parentActiveItems.some((i) => this.containsPath(this.id, i));
    },

    hasContent() {
      return this.$slots.content || this.list;
    },

    hasTitle() {
      return this.icon || this.title || this.$slots.default || this.iconRight;
    },

    opened() {
      return this.parentOpenItems.includes(this.id);
    },

    rounded() {
      let rounded = this.parentItemRounded ?? this.parentRounded;
      if (this.parent) {
        const index = this.parent.children.indexOf(this.id);
        if (index !== 0 || this.parent.hasTitle) {
          rounded += " rounded-t-none";
        }
        if (index !== this.parent.children.length - 1) {
          rounded += " rounded-b-none";
        }
      }
      return rounded;
    },
  },

  watch: {
    activeItems() {
      if (this.parentMultiple) {
        const clearedActiveItems = this.parentActiveItems.filter(
          (i) => !this.containsPath(this.id, i)
        );
        this.parent.activeItems = [...clearedActiveItems, ...this.activeItems];
      } else {
        this.parent.activeItems = [...this.activeItems];
      }
    },

    openItems() {
      if (!(this.openItems.length || this.parentOpenItems.includes(this.id)))
        return;
      const openItems = this.openItems;
      if (this.opened) openItems.push(this.id);
      if (this.parentAccordeon || this.absolute) {
        this.parent.openItems = [...openItems];
      } else {
        const cleared = this.parent.openItems.filter(
          (i) => !this.containsPath(this.id, i)
        );
        this.parent.openItems = [...cleared, ...openItems];
      }
    },

    opened() {
      if (this.opened) {
        this.computedOpened = this.opened;
        this.$nextTick(() => {
          this.initMenuDirection();
          this.openAnimation();
        });
      } else {
        this.closeAnimation();
        if (this.absolute) {
          this.computedOpened = this.opened;
        } else {
          const content = this.$refs.content;
          const height = content.clientHeight;
          const duration = Math.max(0.2, (height / 500) * 0.2); // 0.2s на каждые 500 пикс
          setTimeout(() => {
            this.computedOpened = this.opened;
          }, duration * 1000);
        }
      }
    },

    "$route.path"() {
      this.initIsActive();
    },
  },

  created() {
    this.absolute = this.parentAbsolute || this.mini;
    this.getParent();
    this.id = `${this.parent.id}${this.parent.children.length}`;
    this.parent.children.push(this.id);
  },

  mounted() {
    this.initIsActive();
    window.addEventListener("resize", this.initMenuDirection);
  },

  unmounted() {
    window.removeEventListener("resize", this.initMenuDirection);
  },

  methods: {
    containsPath(findMe, str) {
      const findMeArray = findMe.split("/").filter((i) => i != "");
      const strArray = str.split("/").filter((i) => i != "");
      return findMeArray.every((i, idx) => i === strArray[idx]);
    },

    click() {
      if (this.disabled || this.to) return;
      if (this.to && this.containsPath(this.to, this.$route.path)) return;
      if (this.submenu) {
        if (this.opened) {
          this.closeItem();
        } else {
          this.openItem();
        }
      } else {
        if (this.active) {
          this.unselectItem();
        } else {
          this.selectItem();
        }
      }
    },

    closeAnimation() {
      const content = this.$refs.content;
      const height = content.clientHeight;
      const duration = Math.max(0.2, (height / 500) * 0.2); // 0.2s на каждые 500 пикс
      content.style.height = `${height}px`;
      setTimeout(() => {
        content.style.transition = `height ${duration}s ease-out`;
        content.style.height = 0;
        setTimeout(() => {
          content.style.transition = "none";
          content.style.height = "auto";
        }, duration * 1000);
      }, 0);
    },

    closeItem() {
      this.parent.openItems = this.parent.openItems.filter(
        (i) => i !== this.id
      );
    },

    getParent() {
      let component = null;
      let parent = this.$parent;
      while (parent && !component) {
        if (parent.$options.name === "NvList") {
          component = parent;
        }
        parent = parent.$parent;
      }
      this.parent = component;
    },

    initMenuDirection() {
      const content = this.$refs.content;
      if (!content) return;
      this.absolute = this.parentAbsolute || this.mini;
      this.openToLeft = false;
      this.$nextTick(() => {
        const box = content.getBoundingClientRect();
        if (box.right > document.documentElement.clientWidth) {
          this.openToLeft = true;
          this.$nextTick(() => {
            let box = content.getBoundingClientRect();
            if (box.left < 0) this.absolute = false;
          });
        }
      });
    },

    initIsActive() {
      if (!this.to) return;
      this.$nextTick(() => {
        if (this.containsPath(this.to, this.$route.path)) {
          this.selectItem();
        }
        9;
      });
    },

    openAnimation() {
      const content = this.$refs.content;
      const height = content.clientHeight;
      const duration = Math.max(0.2, (height / 500) * 0.2); // 0.2s на каждые 500 пикс
      content.style.height = 0;
      setTimeout(() => {
        content.style.transition = `height ${duration}s ease-out`;
        content.style.height = `${height}px`;
        setTimeout(() => {
          content.style.transition = "none";
          content.style.height = "auto";
        }, duration * 1000);
      }, 0);
    },

    openItem() {
      this.openItems = [this.id];
    },

    selectItem() {
      if (this.parentAbsolute) {
        this.parent.openItems = this.parent.openItems.filter(
          (i) => i === this.id
        );
      }

      if (this.parentMultiple) {
        this.activeItems = [...this.activeItems, this.id];
      } else {
        this.activeItems = [this.id];
      }
    },

    unselectItem() {
      this.activeItems = this.activeItems.filter((i) => i != this.id);
    },
  },
};
</script>

<style lang="scss" scoped>
.nv-list-item {
  @apply cursor-default flex flex-col relative;
}

.nv-list-item__title {
  @apply flex items-center min-h-[44px] px-5 py-2 hover:bg-gray-100;
}

.dark > .nv-list-item__title {
  @apply hover:bg-[#3c3c3c];
}

.active > .nv-list-item__title {
  @apply bg-primary text-white hover:bg-primary-darken;
}

.dark.disabled > .nv-list-item__title {
  @apply bg-black;
}

.disabled > .nv-list-item__title {
  @apply bg-gray-100 opacity-60;
}

.opened > .nv-list-item__title {
  @apply bg-gray-100;
}

.submenu.active > .nv-list-item__title {
  @apply bg-primary-lighten hover:bg-primary-darken;
}

.dark.opened > .nv-list-item__title {
  @apply bg-[#3c3c3c];
}

.dark.submenu.active > .nv-list-item__title {
  @apply bg-primary-lighten hover:bg-primary-darken;
}

.nv-list-item__title-content {
  @apply flex items-center grow;
}

.nv-list-item__title-text {
  @apply grow;
}

.nv-list-item__title-arrow {
  @apply ml-4;
  transition: transform 0.2s;
}

.opened:not(.absoluteClass)
  > .nv-list-item__title
  > .nv-list-item__title-content
  > .nv-list-item__title-arrow {
  @apply rotate-90;
}

.absoluteClass > .nv-list-item__content {
  @apply absolute left-full shadow-md top-0 z-10 overflow-visible;
  // max-h-screen overflow-y-auto
  &.openToLeft {
    @apply left-auto right-full;
  }
}

.nv-list-item__content {
  @apply overflow-hidden;
  transition: height 0.2s ease-out;
}

.nv-list-item__hotkey {
  @apply opacity-50 ml-4;
}

.nv-navigation-drawer .nv-list-item__title {
  @apply min-h-[64px] font-normal;
}

.nv-list-item__divider {
  @apply border-black/10;
}

.dark > .nv-list-item__divider {
  @apply border-white/30;
}
</style>
