<template>
  <nav>
    <ul>
      <li v-for="item in currentItems" :key="item.label">
        <div class="parent-container" v-if="hasSubItems(item)">
          <template v-if="item.link">
            <BmsLink
              :to="item.link"
              :class="`parent-item is-clickable ${isItemActive(item as ParentMenuItem) ? 'active' : ''}`"
            >
              <span class="parent-label">{{ item.label }}</span>
              <component
                v-if="item.icon"
                :is="item.icon"
                class="parent-item__custom-icon"
              />
            </BmsLink>
          </template>
          <template v-else>
            <div
              v-if="isCollapsible(item as ParentMenuItem)"
              class="parent-item is-clickable"
              @click="toggleParentItem(item as ParentMenuItem)"
            >
              <span class="parent-label">{{ item.label }}</span>
              <ChevronDown v-if="!(item as ParentMenuItem).open" />
              <ChevronUp v-else />
            </div>
            <div v-else class="parent-item">
              <span class="parent-label">{{ item.label }}</span>
            </div>
          </template>
          <Transition name="open">
            <ul
              v-show="
                !isCollapsible(item as ParentMenuItem) ||
                (item as ParentMenuItem).open
              "
            >
              <li
                v-for="subItem in (item as ParentMenuItem).items"
                :key="subItem.label"
              >
                <UiMenuItem
                  :item="subItem as MenuItem"
                  :active="isItemActive(subItem as MenuItem)"
                  @click="clickItem(subItem)"
                >
                  <template #icon-end>
                    <slot name="icon-end" :item="subItem"> </slot>
                  </template>
                </UiMenuItem>
              </li>
            </ul>
          </Transition>
        </div>
        <UiMenuItem
          v-else
          :item="item as MenuItem"
          :active="isItemActive(item as MenuItem)"
          @click="clickItem(item)"
        >
          <template #icon-end>
            <slot name="icon-end" :item="item"> </slot>
          </template>
        </UiMenuItem>
      </li>
    </ul>
    <div class="additional">
      <slot name="additional" :closeMenu="closeMenu"></slot>
    </div>
  </nav>
</template>

<script lang="ts" setup>
import { MenuItem, ParentMenuItem } from '@/models/menu.model';
import { Ref, ref, watchEffect } from 'vue';
import {
  RouteLocationNamedRaw,
  RouteLocationNormalizedLoaded,
  RouteLocationPathRaw,
  RouteLocationRaw,
} from 'vue-router';
import { ChevronDown, ChevronUp, Settings } from 'lucide-vue-next';
import UiMenuItem from './UiMenuItem.vue';
import BmsLink from './BmsLink.vue';
import BmsBadge from '../feedback/BmsBadge.vue';

interface Props {
  items: (MenuItem | ParentMenuItem)[];
  activeLink: RouteLocationNormalizedLoaded;
}

const props = withDefaults(defineProps<Props>(), {});
const emits = defineEmits<{
  (e: 'closeMenu', payload: boolean): void;
  (e: 'clickItem', payload: ParentMenuItem | MenuItem | null): void;
}>();

const hasSubItems = (item: MenuItem | ParentMenuItem) => {
  return item.hasOwnProperty('items');
};

const isCollapsible = (item: ParentMenuItem) => item.collapsible !== false;

const currentItems: Ref<(MenuItem | ParentMenuItem)[]> = ref([]);

const isLinkRecognized = (link: RouteLocationRaw): boolean => {
  if ((link as RouteLocationNamedRaw).name) {
    return (link as RouteLocationNamedRaw).name === props.activeLink.name;
  }
  if ((link as RouteLocationPathRaw).path) {
    return (link as RouteLocationPathRaw).path === props.activeLink.path;
  }
  return (
    link === props.activeLink.name ||
    link === props.activeLink.path ||
    link === props.activeLink
  );
};

const isItemActive = (menuItem: MenuItem | ParentMenuItem): boolean => {
  if (props.activeLink?.meta?.menuItemId) {
    return props.activeLink.meta.menuItemId === menuItem.id;
  } else if (menuItem?.link) {
    return isLinkRecognized(menuItem.link);
  } else {
    return false;
  }
};

watchEffect(() => {
  currentItems.value = props.items.map((item) => {
    if (!hasSubItems(item)) {
      return item;
    }
    const parentItem: ParentMenuItem = item as ParentMenuItem;
    if (!isCollapsible(parentItem)) {
      parentItem.open = true;
      return parentItem;
    }
    if (parentItem.open) {
      return parentItem;
    }
    parentItem.open =
      parentItem.open === undefined ||
      !!parentItem.items.find(isItemActive) ||
      !!parentItem.link;
    return parentItem;
  });
});

const closeMenu = () => {
  emits('closeMenu', false);
};

const clickItem = (payload: ParentMenuItem | MenuItem) => {
  emits('closeMenu', false);
  emits('clickItem', payload);
};

const toggleParentItem = (item: ParentMenuItem) => {
  item.open = !item.open;
};
</script>

<style lang="scss" scoped>
nav {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  overflow: auto;
  padding: 6rem 0 2rem;
  background-color: var(--bms-white);

  ul {
    margin: 0;
    padding: 0;

    li {
      display: flex;
      align-items: center;
      list-style-type: none;
      width: 100%;

      .parent-container {
        width: 100%;

        .parent-item {
          display: flex;
          justify-content: space-between;
          align-items: center;
          color: var(--bms-grey-75);
          padding: 14px 8px;

          :deep(.internal-link) {
            color: inherit;
          }

          &__custom-icon {
            width: 1em;
            height: 1em;
          }

          &.is-clickable {
            cursor: pointer;
          }

          &.is-clickable:hover {
            color: var(--bms-main-100);
            text-decoration: none;
          }

          .parent-label {
            line-height: 16px;
            font-size: 14px;
            text-transform: uppercase;
          }
        }
      }
    }
  }
  .additional {
    display: flex;
    flex-direction: column;
    flex-grow: 1;
  }
}

.open-enter-active {
  transition: all 0.7s ease;
}
.open-leave-active {
  transition: all 0.25s linear;
}

.open-enter-from,
.open-leave-to {
  max-height: 0;
  opacity: 0;
}

.open-enter-to,
.open-leave-from {
  max-height: 500px;
  opacity: 1;
}
</style>
