<script lang="ts" setup>
import { onUnmounted } from 'vue';
import { ref } from 'vue';
import { onMounted } from 'vue';

type Menu = {
  element?: HTMLElement;
  anchor: string;
  name: string;
  sub?: boolean;
  tab?: string;
};

const props = defineProps<{
  menu: Menu[];

  scrollElement?: Element | HTMLElement | string;

  foreground?: string;
  background?: string;

  active?: {
    foreground?: string;
    background?: string;
  };
}>();

const currentScrollElement = ref<Element | HTMLElement>();

function handleClick(menu: Menu) {
  const element = document.getElementById(menu.anchor);

  if (element) {
    element.scrollIntoView({
      behavior: 'smooth',
      block: 'start',
    });
  }
}

const activeMenu = ref(props.menu.at(0)?.anchor || '');

function onScroll() {
  let current = activeMenu.value;

  if (!currentScrollElement.value) return;

  const container = currentScrollElement.value;

  props.menu.forEach((v) => {
    if (!v.element) v.element = document.getElementById(v.anchor) || undefined;
    if (!v.element) return;

    const containerRect = container.getBoundingClientRect();
    const elementRect = v.element.getBoundingClientRect();

    if (containerRect.y + containerRect.height / 5 >= elementRect.y) {
      current = v.anchor;
    }
  });
  activeMenu.value = current;
}

onMounted(() => {
  if (typeof props.scrollElement === 'string' || !props.scrollElement) {
    const element = document.querySelector(props.scrollElement || 'body');
    if (element) currentScrollElement.value = element;
  } else {
    currentScrollElement.value = props.scrollElement;
  }

  currentScrollElement.value?.addEventListener('scroll', onScroll);
});
onUnmounted(() => {
  currentScrollElement.value?.removeEventListener('scroll', onScroll);
});
</script>

<template>
  <div class="side-menu__container">
    <template v-for="v in menu" :key="v.anchor">
      <span
        :style="{
          '--side-menu__fg': activeMenu !== v.anchor ? foreground : undefined,
          '--side-menu__bg': activeMenu !== v.anchor ? background : undefined,
          '--side-menu__fg-active': active?.foreground,
          '--side-menu__bg-active': active?.background,
        }"
        class="side-menu__item"
        :class="{
          'side-menu__active': activeMenu === v.anchor,
          'side-menu__sub': v.sub || false,
        }"
        @click="handleClick(v)"
      >
        {{ v.name }}
      </span>
    </template>
  </div>
</template>

<style scoped>
.side-menu__container {
  display: flex;
  flex-direction: column;
  gap: var(--size-1);
  max-width: 100%;

  & > .side-menu__item {
    transition: 0.3s background ease-in-out;
    color: var(--side-menu__fg, inherit);
    background: var(--side-menu__bg, inherit);
    padding: var(--size-2) var(--size-4);
    border-radius: var(--radius-2);
    cursor: pointer;

    &.side-menu__sub {
      margin-left: 1rem;
    }

    &.side-menu__active {
      --side-menu__fg: var(--side-menu__fg-active, inherit);
      --side-menu__bg: var(--side-menu__bg-active, inherit);
      font-weight: 600;
    }
  }
}
</style>
