<template>
  <div>
    <div class="nav-container" :class="{ open: isNavigationOpen }">
      <nav ref="nav" :aria-label="$t('appNavigation.primaryNavigation')">
        <b-nav vertical class="mb-4">
          <template v-for="navItem in navigationItems">
            <!-- Navigation items with no children -->
            <li
              v-if="!navItem.children"
              :key="`nav-${navItem.index}`"
              class="nav-item"
            >
              <router-link
                :to="navItem.route"
                :data-test-id="`nav-item-${navItem.id}`"
                class="nav-link"
              >
                <component :is="navItem.icon" />
                {{ navItem.label }}
              </router-link>
            </li>

            <!-- Navigation items with children -->
            <li v-else :key="`nav-group-${navItem.index}`" class="nav-item">
              <b-button
                :class="{ collapsed: !isItemOpen(navItem.id) }"
                variant="link"
                :data-test-id="`nav-button-${navItem.id}`"
                :aria-controls="navItem.id"
                :aria-expanded="isItemOpen(navItem.id) ? 'true' : 'false'"
                @click="toggleCollapse(navItem.id)"
              >
                <component :is="navItem.icon" />
                {{ navItem.label }}
                <icon-expand class="icon-expand" />
              </b-button>
              <b-collapse
                :id="navItem.id"
                v-model="openSections[navItem.id]"
                tag="ul"
                class="nav-item__nav"
              >
                <li
                  v-for="(subNavItem, i) in filteredNavItem(navItem.children)"
                  :key="i"
                  class="nav-item"
                >
                  <router-link
                    :to="subNavItem.route"
                    :data-test-id="`nav-item-${subNavItem.id}`"
                    class="nav-link"
                  >
                    {{ subNavItem.label }}
                  </router-link>
                </li>
              </b-collapse>
            </li>
          </template>
        </b-nav>
      </nav>
    </div>
    <transition name="fade">
      <div
        v-if="isNavigationOpen"
        id="nav-overlay"
        class="nav-overlay"
        @click="toggleIsOpen"
      ></div>
    </transition>
  </div>
</template>

<script>
//Do not change Mixin import.
//Exact match alias set to support
//dotenv customizations.
import AppNavigationMixin from './AppNavigationMixin';
import { useI18n } from 'vue-i18n';

export default {
  name: 'AppNavigation',
  mixins: [AppNavigationMixin],
  data() {
    return {
      $t: useI18n().t,
      isNavigationOpen: false,
      currentUserRole: null,
      openSections: {},
    };
  },
  watch: {
    $route: function () {
      this.isNavigationOpen = false;
      // Ensure the parent section of the current route is expanded
      this.initializeOpenSectionsFromRoute();
    },
    isNavigationOpen: function (isNavigationOpen) {
      require('@/eventBus').default.$emit(
        'change-is-navigation-open',
        isNavigationOpen,
      );
    },
  },
  mounted() {
    this.getPrivilege();
    require('@/eventBus').default.$on('toggle-navigation', () =>
      this.toggleIsOpen(),
    );
    // Expand the parent section for the current route on initial load/refresh
    this.initializeOpenSectionsFromRoute();
  },
  beforeUnmount() {
    require('@/eventBus').default.$off(
      'toggle-navigation',
      this.handleToggleNavigation,
    );
  },
  methods: {
    isItemOpen(id) {
      return !!this.openSections[id];
    },
    toggleCollapse(id) {
      if (this.$set) {
        this.$set(this.openSections, id, !this.openSections[id]);
      } else {
        this.openSections = {
          ...this.openSections,
          [id]: !this.openSections[id],
        };
      }
    },
    toggleIsOpen() {
      this.isNavigationOpen = !this.isNavigationOpen;
    },
    getPrivilege() {
      this.currentUserRole = this.$store?.getters['global/userPrivilege'];
    },
    filteredNavItem(navItem) {
      if (this.currentUserRole) {
        return navItem.filter(({ exclusiveToRoles }) => {
          if (!exclusiveToRoles?.length) return true;
          return exclusiveToRoles.includes(this.currentUserRole);
        });
      } else return navItem;
    },
    initializeOpenSectionsFromRoute() {
      const currentPath = this.$route?.path;
      if (!currentPath) return;
      const sectionsToOpen = {};
      for (const item of this.navigationItems) {
        if (
          item.children &&
          item.children.some((child) => child.route === currentPath)
        ) {
          sectionsToOpen[item.id] = true;
        }
      }
      this.openSections = { ...this.openSections, ...sectionsToOpen };
    },
  },
};
</script>

<style scoped lang="scss">
svg {
  fill: currentColor;
  height: 1.2rem;
  width: 1.2rem;
  margin-inline-start: 0 !important; //!important overriding button specificity
  vertical-align: text-bottom;
  &:not(.icon-expand) {
    margin-inline-end: $spacer;
  }
}

.nav {
  padding-top: calc(#{$spacer} / 4);
  @include media-breakpoint-up($responsive-layout-bp) {
    padding-top: $spacer;
  }
}

.nav-item__nav {
  list-style: none;
  padding-inline-start: 0;
  margin-inline-start: 0;

  .nav-item {
    outline: none;
    list-style: none;
  }

  .nav-link {
    padding-inline-start: $spacer * 4;
    outline: none;

    &:not(.nav-link--current) {
      font-weight: normal;
    }
  }
}

.btn-link {
  display: inline-block;
  width: 100%;
  text-align: start;
  text-decoration: none !important;
  border-radius: 0;

  &.collapsed {
    .icon-expand {
      transform: rotate(180deg);
    }
  }
}

.icon-expand {
  float: inline-end;
  margin-top: calc(#{$spacer} / 4);
}

.btn-link,
.nav-link {
  position: relative;
  font-weight: $headings-font-weight;
  padding-inline-start: $spacer; // defining consistent padding for links and buttons
  padding-inline-end: $spacer;
  color: theme-color('secondary');

  &:hover {
    background-color: theme-color-level(dark, -10.5);
    color: theme-color('dark');
  }

  &:focus {
    background-color: theme-color-level(light, 0);
    box-shadow: inset 0 0 0 2px theme-color('primary');
    color: theme-color('dark');
    outline: 0;
  }

  &:active {
    background-color: theme-color('secondary');
    color: $white;
  }
}

.nav-link--current {
  font-weight: $headings-font-weight;
  background-color: theme-color('secondary');
  color: theme-color('light');
  cursor: default;
  box-shadow: none;

  &::before {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    inset-inline-start: 0;
    width: 4px;
    background-color: theme-color('primary');
  }

  &:hover,
  &:focus {
    background-color: theme-color('secondary');
    color: theme-color('light');
  }
}

.nav-container {
  position: fixed;
  width: $navigation-width;
  top: $header-height;
  bottom: 0;
  left: 0;
  z-index: $zindex-fixed;
  overflow-y: auto;
  background-color: theme-color('light');
  transform: translateX(-$navigation-width);
  transition: transform $exit-easing--productive $duration--moderate-02;
  border-inline-end: 1px solid theme-color-level('light', 2.85);

  @include media-breakpoint-down(md) {
    z-index: $zindex-fixed + 2;
  }

  &.open,
  &:focus-within {
    transform: translateX(0);
    transition-timing-function: $entrance-easing--productive;
  }

  @include media-breakpoint-up($responsive-layout-bp) {
    transition-duration: $duration--fast-01;
    transform: translateX(0);
  }
}

.nav-overlay {
  position: fixed;
  top: $header-height;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: $zindex-fixed + 1;
  background-color: $black;
  opacity: 0.5;

  &.fade-enter-active {
    transition: opacity $duration--moderate-02 $entrance-easing--productive;
  }

  &.fade-leave-active {
    transition: opacity $duration--fast-02 $exit-easing--productive;
  }

  &.fade-enter, // Remove this vue2 based only class when switching to vue3
  &.fade-enter-from, // This is vue3 based only class modified from 'fade-enter'
  &.fade-leave-to {
    opacity: 0;
  }

  @include media-breakpoint-up($responsive-layout-bp) {
    display: none;
  }
}
</style>
