<script setup>

import { ref, computed, useTemplateRef, watch, inject } from 'vue';
import SideBarItem from './SideBarItem.vue';

const isMobile = inject('isMobile');

const emit = defineEmits(['close']);

const props = defineProps({
  label: {
    type: String,
  },
  icon: {
    type: String,
  },
  route: {
    type: String,
  },
  active: {
    type: [ Boolean, Function ],
    default: false,
  },
  separator: {
    type: Boolean,
    default: false,
  },
  collapsed: {
    type: Boolean,
    default: false,
  },
  visible: {
    type: [ Boolean, Function ],
    default: true,
  },
  childItems: {
    type: Array,
    default: () => [],
  }
});

const isMenuExpanded = ref(false);
const isMenuOpen = ref(false);

watch(() => props.collapsed, () => {
  isMenuExpanded.value = false;
  isMenuOpen.value = false;
});

const isActive = computed(() => {
  const active = props.active;
  return typeof active === 'function' ? active() : active ?? true;
});

const isVisible = computed(() => {
  const visible = props.visible;
  return typeof visible === 'function' ? visible() : visible ?? true;
});

function close() {
  isMenuOpen.value = false;
  emit('close');
}

const subMenuElement = useTemplateRef('subMenuElement');
const elem = useTemplateRef('elem');

function getViewport() {
  const win = window,
    d = document,
    e = d.documentElement,
    g = d.getElementsByTagName('body')[0],
    w = win.innerWidth || e.clientWidth || g.clientWidth,
    h = win.innerHeight || e.clientHeight || g.clientHeight;

  return {
    width: w,
    height: h
  };
}

function getHiddenElementSize(element) {
  if (element) {
    const originalVisibility = element.style.visibility;
    const originalDisplay = element.style.display;

    element.style.visibility = 'hidden';
    element.style.display = 'block';

    element.clientHeight; // force reflow

    const height = element.offsetHeight;
    const width = element.offsetWidth;

    element.style.display = originalDisplay;
    element.style.visibility = originalVisibility;

    return { height, width };
  }
  return { height: 0, width: 0 };
}

const subMenuFlipped = ref(false);
function toggleMenu() {
  if (props.collapsed && !isMobile.value) {
    const size = getHiddenElementSize(subMenuElement.value);
    const viewport = getViewport();

    // rect of triggering element
    const top = elem.value.getBoundingClientRect().top;
    const bottom = elem.value.getBoundingClientRect().bottom;
    const right = elem.value.getBoundingClientRect().right;

    // vertically flip or not
    subMenuFlipped.value = false;
    let menuTop = top;
    if (top + size.height - document.body.scrollTop > viewport.height) {
      if (top - document.body.scrollTop > viewport.height/2) {
        menuTop = bottom - size.height;
        subMenuFlipped.value = true;
      }
    }

    subMenuElement.value.style.left = right + 10 + 'px';
    subMenuElement.value.style.top = menuTop + 'px';

    isMenuOpen.value = true;
  } else {
    isMenuExpanded.value = !isMenuExpanded.value;
  }
}

function onBackdrop(event) {
  isMenuOpen.value = false;
  event.preventDefault();
}

</script>

<template>
  <div v-if="isVisible">
    <hr v-if="separator"/>
    <a v-else-if="!childItems?.length" class="sidebar-item" :class="{ active: isActive }" :href="route" @click="close()" v-tooltip.right="collapsed && !isMobile ? label : null"><i :class="icon"></i> <span :class="{ 'sidebar-item-label-collapsed': collapsed }">{{ label }}</span></a>
    <div v-else-if="childItems.length" ref="elem" class="sidebar-item" :class="{ 'sidebar-item-menu-open': isMenuOpen ? '#e9ecef' : null }" @click="toggleMenu()" v-tooltip.right="collapsed && !isMobile ? label : null"><i :class="icon"></i> <span :class="{ 'sidebar-item-label-collapsed': collapsed }">{{ label }} <i class="collapse fa-solid fa-angle-right" :class="{ expanded: isMenuExpanded }" style="margin-left: 6px;"></i></span></div>

    <teleport to="#app">
      <div class="pankow-menu-backdrop" @click="onBackdrop($event)" @contextmenu="onBackdrop($event)" v-show="isMenuOpen"></div>
      <div v-show="isMenuOpen" ref="subMenuElement" class="sidebar-item-menu">
        <div :class="{ 'sidebar-item-menu-anchor': !subMenuFlipped }">
          <span class="sidebar-item-header">{{ label }}</span>
        </div>
        <div v-for="(item, index) in childItems" :key="item" :class="{ 'sidebar-item-menu-anchor': subMenuFlipped && index === childItems.length-1 }">
          <hr v-if="item.separator"/>
          <a v-else class="sidebar-item" :href="item.route" @click="close()"><i :class="item.icon"></i> {{ item.label }}</a>
        </div>
      </div>
    </teleport>

    <Transition name="sidebar-item-group-animation">
      <div class="sidebar-item-group" v-if="isMenuExpanded">
        <SideBarItem v-for="item in childItems" :key="item"
          :label="item.label"
          :icon="item.icon"
          :route="item.route"
          :visible="item.visible"
          :active="item.active"
          :separator="item.separator"
          :child-items="item.childItems"
          @close="close()"
        />
      </div>
    </Transition>
  </div>
</template>

<style scoped>

.sidebar-item-menu {
  position: absolute;
  z-index: 3002; /* backdrop is at 3001 -> see pankow */
  background-color: var(--navbar-background);
  border-top-right-radius: var(--pankow-border-radius);
  border-bottom-right-radius: var(--pankow-border-radius);
}

.sidebar-item-menu-open {
  background-color: #e9ecef;
}

.sidebar-item-menu-anchor::before {
  content: "";
  position: absolute;
  left: -20px;
  width: 20px;
  height: 37px;
  background-color: #e9ecef;
}

.sidebar-item-header {
  background-color: #e9ecef;
  display: block;
  font-weight: var(--pankow-font-weight-bold);
  color: var(--pankow-text-color);
  padding: 10px 15px;
  white-space: nowrap;
  border-radius: 0;
  border-top-right-radius: var(--pankow-border-radius);
}

.sidebar-item {
  display: block;
  color: var(--pankow-text-color);
  border-radius: 3px;
  padding: 10px 15px;
  white-space: nowrap;
  cursor: pointer;
}

.sidebar-item i {
  opacity: 0.7;
  margin-right: 10px;
}

.sidebar-item.active {
  color: var(--pankow-color-primary);
  text-decoration: none;
  font-weight: var(--pankow-font-weight-bold);
}

.sidebar-item:hover {
  background-color: #e9ecef;
  text-decoration: none;
}

@media (prefers-color-scheme: dark) {
  .sidebar-item-header,
  .sidebar-item:hover,
  .sidebar-item-menu-open,
  .sidebar-item-menu-anchor::before {
    background-color: #282d38;
  }
}

.sidebar-item.active i ,
.sidebar-item:hover i {
  opacity: 1;
}

.sidebar-item-label-collapsed {
  display: none;
}

@media (max-width: 576px) {
  .sidebar-item-label-collapsed {
    display: inline-block;
  }
}

.sidebar-item-group {
  padding-left: 20px;
  height: auto;
  overflow: hidden;
  /* we need height to auto so we animate max-height. needs to be bigger than we need */
  max-height: 300px;
}

.sidebar-item-group-animation-enter-active,
.sidebar-item-group-animation-leave-active {
  transition: all 0.2s linear;
}

.sidebar-item-group-animation-leave-to,
.sidebar-item-group-animation-enter-from {
  transform: translateX(-100px);
  opacity: 0;
  max-height: 0;
}

.slide-fade-enter-active {
  transition: all 0.1s ease-out;
}

.slide-fade-leave-active {
  transition: all 0.1s ease-out;
}

.slide-fade-enter-from,
.slide-fade-leave-to {
  transform: translateX(20px);
  opacity: 0;
}

</style>