<template>
  <div class="relative h-9 w-9" v-click-outside="clickOutsideObj">
    <slot :disabled="disabled" :showMenu="showMenu" :clickShowMenu="clickShowMenu" :processing="processing">
      <button v-if="!processing" type="button" :disabled="disabled" class="relative h-full w-full flex items-center justify-center shadow-sm pl-3 pr-3 text-left focus:outline-none cursor-pointer text-gray-100 hover:text-gray-200 rounded-full hover:bg-white/5" aria-haspopup="listbox" :aria-expanded="showMenu" @click.stop.prevent="clickShowMenu">
        <span class="material-symbols" :class="iconClass">more_vert</span>
      </button>
      <div v-else class="h-full w-full flex items-center justify-center">
        <widgets-loading-spinner />
      </div>
    </slot>

    <transition name="menu">
      <div v-show="showMenu" ref="menuWrapper" class="absolute right-0 mt-1 z-10 bg-bg border border-black-200 shadow-lg rounded-md py-1 focus:outline-none sm:text-sm" :style="{ width: menuWidth + 'px' }">
        <template v-for="(item, index) in items">
          <template v-if="item.subitems">
            <div :key="index" class="flex items-center px-2 py-1.5 hover:bg-white/5 text-white text-xs cursor-default" :class="{ 'bg-white/5': mouseoverItemIndex == index }" @mouseover="mouseoverItem(index)" @mouseleave="mouseleaveItem(index)" @click.stop>
              <p>{{ item.text }}</p>
            </div>
            <div
              v-if="mouseoverItemIndex === index"
              :key="`subitems-${index}`"
              @mouseover="mouseoverSubItemMenu(index)"
              @mouseleave="mouseleaveSubItemMenu(index)"
              class="absolute bg-bg border rounded-b-md border-black-200 shadow-lg z-50 -ml-px py-1"
              :class="openSubMenuLeft ? 'rounded-l-md' : 'rounded-r-md'"
              :style="{ left: submenuLeftPos + 'px', top: index * 28 + 'px', width: submenuWidth + 'px' }"
            >
              <div v-for="(subitem, subitemindex) in item.subitems" :key="`subitem-${subitemindex}`" class="flex items-center px-2 py-1.5 hover:bg-white/5 text-white text-xs cursor-pointer" @click.stop="clickAction(subitem.action, subitem.data)">
                <p>{{ subitem.text }}</p>
              </div>
            </div>
          </template>
          <div v-else :key="index" class="flex items-center px-2 py-1.5 hover:bg-white/5 text-white text-xs cursor-pointer" @click.stop="clickAction(item.action)">
            <p class="text-left">{{ item.text }}</p>
          </div>
        </template>
      </div>
    </transition>
  </div>
</template>

<script>
export default {
  props: {
    disabled: Boolean,
    items: {
      type: Array,
      default: () => []
    },
    iconClass: {
      type: String,
      default: ''
    },
    menuWidth: {
      type: Number,
      default: 192
    },
    processing: Boolean
  },
  data() {
    return {
      clickOutsideObj: {
        handler: this.clickedOutside,
        events: ['mousedown'],
        isActive: true
      },
      submenuWidth: 144,
      showMenu: false,
      mouseoverItemIndex: null,
      isOverSubItemMenu: false,
      openSubMenuLeft: false
    }
  },
  computed: {
    submenuLeftPos() {
      return this.openSubMenuLeft ? -(this.submenuWidth - 1) : this.menuWidth - 0.5
    }
  },
  methods: {
    mouseoverSubItemMenu(index) {
      this.isOverSubItemMenu = true
    },
    mouseleaveSubItemMenu(index) {
      setTimeout(() => {
        if (this.isOverSubItemMenu && this.mouseoverItemIndex === index) this.mouseoverItemIndex = null
      }, 1)
    },
    mouseoverItem(index) {
      this.isOverSubItemMenu = false
      this.mouseoverItemIndex = index
    },
    mouseleaveItem(index) {
      setTimeout(() => {
        if (this.isOverSubItemMenu) return
        if (this.mouseoverItemIndex === index) this.mouseoverItemIndex = null
      }, 1)
    },
    clickShowMenu() {
      if (this.disabled) return
      this.showMenu = !this.showMenu
      this.$nextTick(() => {
        const boundingRect = this.$refs.menuWrapper?.getBoundingClientRect()
        if (boundingRect) {
          this.openSubMenuLeft = window.innerWidth - boundingRect.x < this.menuWidth + this.submenuWidth + 5
        }
      })
    },
    clickedOutside() {
      this.showMenu = false
    },
    clickAction(action, data) {
      if (this.disabled) return
      this.showMenu = false
      this.$emit('action', { action, data })
    }
  },
  mounted() {}
}
</script>