<template>
  <nav class="mc-menu" :style="styleObject" :aria-label="ariaLabel">
    <ul class="mc-menu__list">
      <li
        v-for="(item, index) of items"
        :key="item.label"
        class="mc-menu__item"
      >
        <component
          :is="setComponent(item)"
          v-bind="setAttributes(item)"
          class="mc-menu__link"
          :class="classObjectLink(item, index)"
          @click="onElementClicked($event, item, index)"
        >
          <MIcon v-if="item.icon" :name="item.icon" class="mc-menu__icon" />
          <span class="mc-menu__label">{{ item.label }}</span>
        </component>
      </li>
    </ul>
  </nav>
</template>

<script setup>
import { computed, ref, watch } from 'vue';
import MIcon from '../icon/MIcon.vue';

/**
 * > The Menu is a useful component for creating a sub-navigation within a content page.
 *
 * The `MMenu` component is the **Vue.js** implementation of the **Built-In Menu** component of Mozaic Design System.<br/>
 * The full specification of this component is available in [the associated documentation](https://mozaic.adeo.cloud/components/built-in-menu/).
 */

/** props */
const props = defineProps({
  /**
   * An array of objects that allows you to provide all the data needed to generate the items of the Menu.
   * @type {[{ label: String, icon: String, href: String, route: String, class: String, disabled: Boolean }]}
   */
  items: {
    type: Array,
    default: null,
  },
  /**
   * A brief description of the purpose of the navigation, omitting the term "navigation", as the screen reader will read both the HTML tag and the contents of the label.
   */
  ariaLabel: {
    type: String,
    required: true,
  },
  /**
   * Allows you to define a maximum size for the component
   */
  maxWidth: {
    type: String,
    default: null,
  },
  /**
   * Allows to set the active item. _(Should be a `ref()`)_
   */
  modelValue: {
    type: Number,
    default: null,
  },
});

/** emits */
const emit = defineEmits(['update:modelValue', 'click:menu-item']);

/** data */
const activeIndex = ref(0);

/** computed */
const styleObject = computed(() => {
  return {
    '--menu-width': props.maxWidth,
  };
});

/** watch */
watch(
  () => props.modelValue,
  (value) => {
    if (value || value === 0) {
      activeIndex.value = value;
    }
  },
  { immediate: true }
);

/** methods */
const setComponent = (item) => {
  const routerLink = item.route ? 'router-link' : null;
  const linkElement = item.href ? (item.disabled ? 'span' : 'a') : 'button';
  return routerLink ?? linkElement;
};

const setAttributes = (item) => {
  const href = item.href ?? null;
  const target = item.href && item.target ? item.target : null;
  const type = !item.href && !item.route ? 'button' : null;
  const disabled = !item.href && item.disabled ? true : null;
  const to = item.route ?? null;

  return {
    ...item.attrs,
    href,
    target,
    to,
    type,
    disabled,
  };
};

const classObjectLink = (item, index) => {
  return [
    item.class,
    {
      'is-active': activeIndex.value === index,
      'is-disabled': item.disabled,
    },
  ];
};

const onElementClicked = (event, item, itemIndex) => {
  if (item?.disabled) {
    event.preventDefault();

    return;
  }

  if (itemIndex !== activeIndex.value) {
    activeIndex.value = itemIndex;
    /**
     * Triggers when the value of the selected item index changed
     *
     * - @arg {number} [item] - value of the selected item index
     */
    emit('update:modelValue', activeIndex.value);
  }

  if (event) {
    /**
     * Triggers when a item is clicked.
     *
     * - @arg {object} [item] - a js object of values & datas of the item clicked
     * // TODO: Refactoring event naming
     */
    emit('click:menu-item', { index: itemIndex, ...item });
  }
};
</script>

<style lang="scss" scoped>
@import 'settings-tools/all-settings';
@import 'components/c.menu';
</style>
