<template>
  <Menu :as="as" v-slot="{ open }" class="relative" :class="isNested ? '' : 'inline-block'" @mouseover="active=true" @mouseleave="active=false">
    <div ref="menu" class="menu">

    <MenuButton :as="buttonAs" class="rounded-[inherit]">
      <slot name="button" :open="open" :active="active">
        <AisItemLabel :label="label"
                      :class="[buttonClasses, isNested && active ? activeClasses : '']"
                      :icon="icon"
                      :icon-class="iconClass"
                      :arrow-icon="smartArrowIcon"
                      :arrow-class="arrowClass"
        >
          <slot name="button-label" :open="open" :active="active">{{ label }}</slot>
        </AisItemLabel>
      </slot>
    </MenuButton>

    <TransitionRoot :enter="enter"
                    :enter-from="enterFrom"
                    :enter-to="enterTo"
                    :leave="leave"
                    :leave-from="leaveFrom"
                    :leave-to="leaveTo"
    >
      <MenuItems :as="itemsAs" class="absolute z-50 focus:outline-none" :class="itemsClasses" :style="itemsStyles">
        <slot name="default">

          <template v-for="item in items" :key="item.key">
            <AisMenuDivider v-if="item.type === 'divider'"/>

            <BaseMenuGroup v-else-if="item.type === 'group'"
                          :label="item.label"
                          :items="item.items"
                          :header-class="[item.headerClass, itemClass]"
                          :header-as="item.headerAs"/>

            <BaseMenu v-else-if="item.children && item.children.length > 0"
                      :label="item.label"
                      :items="item.children"
                      :class="item.class"
                      :button-class="item.buttonClass || buttonClasses"
                      :active-class="item.activeClass || activeClasses"
                      :item-class="item.itemClass || itemClasses"
                      :items-class="item.itemsClass || itemsClasses"
                      :as="'template'"
                      :button-as="item.buttonAs"
                      :item-as="item.itemAs"
                      :items-as="item.itemsAs"
                      :disabled="disabled || item.disabled"
                      :icon="item.icon"
                      :icon-class="item.iconClass"
                      :arrow-icon="item.arrowIcon"
                      :arrow-class="item.arrowClass"
                      :item-icon-class="itemIconClasses"
            ></BaseMenu>

            <BaseMenuItem v-else
                          :as="item.as || itemAs"
                          :label="item.label"
                          :label-class="item.labelClass"
                          :to="item.to"
                          :href="item.href"
                          :disabled="disabled || item.disabled"
                          :icon="item.icon"
                          :icon-class="item.iconClass"
                          :arrow-icon="item.arrowIcon"
                          :arrow-class="item.arrowClass"
            ></BaseMenuItem>
          </template>


        </slot>
      </MenuItems>
    </TransitionRoot>
    </div>
  </Menu>
</template>

<script setup>
  import { computed, inject, provide, onMounted, ref } from "vue";
  import BaseMenuItem from "@/components/menu/BaseMenuItem.vue";
  import AisItemLabel from "@/components/item-label/AisItemLabel.vue";
  import AisMenuDivider from "@/components/menu/AisMenuDivider.vue";
  import BaseMenuGroup from "@/components/menu/BaseMenuGroup.vue";
  import { TransitionRoot, Menu, MenuButton, MenuItems } from '@headlessui/vue'
  import { transitionProps } from "@/util/transition-props";
  import { baseMenuProps } from "@/components/menu/base-menu-props";
  import { itemLabelProps } from "@/util/item-label-props";

  const menu = ref(null)
  const buttonHeight = ref(0);
  const active = ref(false)     // this is only used when menu is nested inside another menu, used to determine whether to apply active class

  const hasIcon = !!props.icon
  const childIconCount = ref(0)

  const itemsClassInjected = inject('itemsClass', '')
  const itemClassInjected = inject('itemClass', '')
  const itemIconClassInjected = inject('itemIconClass', '')
  const activeClassInjected = inject('activeClass', '')
  const siblingIconCount = inject('siblingIconCount', 0)
  const incrementIconCountNested = inject('incrementIconCount', undefined)
  const navMargin = inject('navMargin', undefined)

  /* To ensure child menus get dropped in the same direction as parent menu, unless specifically overridden */
  const parentRight = inject('parentRight', false)
  const parentDropup = inject('parentDropup', false)
  const parentDropleft = inject('parentDropleft', false)
  const parentDropright = inject('parentDropright', false)

  const props = defineProps({
    ...baseMenuProps,
    ...itemLabelProps,
    ...transitionProps,
  })

  const isNested = computed(() => incrementIconCountNested !== undefined)
  const smartArrowIcon = computed(() => {
    if(props.arrowIcon)
      return props.arrowIcon

    if(isNested.value)
      return 'right'

    if(props.dropleft)    // for dropleft, we want to put the arrow icon in the left 'icon' slot and not the right 'arrow-icon' slot
      return undefined

    return 'down'
  })

  const itemsClasses = computed(() => {
    const classes = []

    if(props.right || props.dropleft)
      classes.push('right-0')
    if(props.dropup)
      classes.push('bottom-0')
    if(props.dropright || (parentDropright.value && !props.dropleft))
      classes.push('left-full')
    if(props.dropleft || parentRight.value || (parentDropleft.value && !props.dropright))
      classes.push('right-full')

    classes.push(itemsClassProvider.value)

    if(!isNested.value && navMargin && navMargin.value !== undefined)
      classes.push(navMargin.value)

    return classes.join(' ')
  })
  const itemsClassProvider = computed(() => {
    if(props.itemsClass) return props.itemsClass

    if(isNested.value && itemsClassInjected.value !== undefined)
      return itemsClassInjected.value

    return ''
  })

  const itemsStyles = computed(() => {
    if(props.dropright || (parentDropright.value && !props.dropleft)
        || props.dropleft || parentRight.value || (parentDropleft.value && !props.dropright)
        || props.dropup || parentDropup.value)
      return `transform: translateY(-${buttonHeight.value}px);`

    return '';
  })

  const itemClasses = computed(() => {
    if(props.itemClass) return props.itemClass

    if(isNested.value && itemClassInjected.value !== undefined)
      return itemClassInjected.value

    return ''
  })

  const itemIconClasses = computed(() => {
    if(props.itemIconClass)
      return props.itemIconClass

    if(itemIconClassInjected.value !== undefined)
      return itemIconClassInjected.value

    return ''
  })

  const buttonClasses = computed(() => {
    if(props.buttonClass) return props.buttonClass

    if(isNested.value) {
      if (itemClassInjected.value !== undefined)
        return itemClassInjected.value
    }

    return ''
  })

  const activeClasses = computed(() => {
    if(props.activeClass) return props.activeClass

    if(isNested.value && activeClassInjected.value !== undefined)
      return activeClassInjected.value

    return ''
  })

  const hasSiblingIcon = computed(() => siblingIconCount.value > 0)

  onMounted(() => {
    buttonHeight.value = menu.value.offsetHeight

    if(hasIcon && isNested.value) incrementIconCountNested()
  })

  const incrementIconCount = () => { childIconCount.value++ }

  provide( 'activeClass', computed(() => activeClasses.value) )
  provide( 'itemsClass', computed(() => itemsClassProvider.value) )
  provide( 'itemClass', computed(() => itemClasses.value) )
  provide( 'itemIconClass', computed(() => itemIconClasses.value) )
  if(!isNested.value)
    provide( 'iconClass', computed(() => props.iconClass) )
  else
    provide( 'iconClass', computed(() => itemIconClasses.value) )
  provide( 'incrementIconCount', incrementIconCount )
  provide( 'hasSiblingIcon', computed(() => hasSiblingIcon.value) )
  provide( 'siblingIconCount', computed(() => childIconCount.value) )

  /* These are only injected by child/nested BaseMenu components (not by BaseMenuItem or BaseMenuGroup) */
  provide( 'parentRight', computed(() => props.right) )
  provide( 'parentDropleft', computed(() => props.dropleft || (parentDropleft.value && !props.dropright)) )
  provide( 'parentDropright', computed(() => props.dropright || (parentDropright.value && !props.dropleft)) )
  provide( 'parentDropup', computed(() => props.dropup) )
</script>

<script>
export default {
  name: "BaseMenu"
}
</script>
