<template>
  <v-list v-model:opened="openedModel" color="primary" density="compact" prepend-gap="8">
    <template v-for="item in menuItems" :key="item.path ?? item.title">
      <v-list-group v-if="item.subItems?.length" class="menu-group" :value="`menu:${item.path ?? item.title}`">
        <template #activator="{ props }">
          <v-list-item
v-bind="isShrink ? undefined : props" :class="{ 'px-0': isShrink }"
            :link="isNavigable(item) && !!item.path" :to="isNavigable(item) ? item.path : undefined" @click="emitSelect(item)">
            <template #prepend>
              <v-icon v-if="item.icon" size="20" :icon="item.icon" />
              <v-btn v-if="isShrink && !item.icon" class="" rounded size="36" spaced="start" variant="text">{{
                item.title?.charAt(0) }}</v-btn>
            </template>
            <template #title>
              <span v-if="!isShrink" class="text-body-2 nav-text-overflow">{{ item.title }}</span>
            </template>
            <template #append>
              <v-chip
v-if="!isShrink && getItemCount(item) > 0" class="menu-count" color="secondary" size="x-small"
                variant="tonal">
                {{ getItemCount(item) }}
              </v-chip>
            </template>
          </v-list-item>
        </template>

        <template v-for="subItem in item.subItems" :key="subItem.path ?? subItem.title">
          <v-list-group
v-if="subItem.subItems?.length"
            class="menu-group" :value="`menu:${item.path ?? item.title}::${subItem.path ?? subItem.title}`">
            <template #activator="{ props: subProps }">
              <v-list-item
v-bind="subProps" :link="isNavigable(subItem)"
                :prepend-icon="subItem.icon || mdiMenuRight" :to="isNavigable(subItem) ? subItem.path : undefined"
                @click="emitSelect(subItem)">
                <template #title>
                  <span class="text-body-2 nav-text-overflow">{{ subItem.title }}</span>
                </template>
                <template #append>
                  <v-chip
v-if="getItemCount(subItem) > 0" class="menu-count" color="secondary" size="x-small"
                    variant="tonal">
                    {{ getItemCount(subItem) }}
                  </v-chip>
                </template>
              </v-list-item>
            </template>

            <v-list-item
v-for="subSubItem in subItem.subItems" :key="subSubItem.path ?? subSubItem.title"
              :link="!!subSubItem.path" :prepend-icon="mdiCircleSmall" :to="subSubItem.path"
              @click="emitSelect(subSubItem)">
              <template #title>
                <v-tooltip location="end" :text="subSubItem.title">
                  <template #activator="{ props: tooltipProps }">
                    <span v-bind="tooltipProps" class="text-body-2 nav-text-overflow">{{ subSubItem.title }}</span>
                  </template>
                </v-tooltip>
              </template>
            </v-list-item>
          </v-list-group>

          <v-list-item
v-else :link="!!subItem.path" :prepend-icon="subItem.icon || mdiMenuRight" :to="subItem.path"
            @click="emitSelect(subItem)">
            <template #title>
              <v-tooltip location="end" :text="subItem.title">
                <template #activator="{ props: tooltipProps }">
                  <span v-bind="tooltipProps" class="text-body-2 nav-text-overflow">{{ subItem.title }}</span>
                </template>
              </v-tooltip>
            </template>
          </v-list-item>
        </template>
      </v-list-group>

      <v-list-item v-else :class="{ 'px-0': isShrink }" :link="!!item.path" :to="item.path" @click="emitSelect(item)">
        <template #prepend>
          <v-icon v-if="item.icon" size="20" :icon="item.icon" />
          <v-btn v-if="isShrink && !item.icon" class="" rounded size="36" spaced="start" variant="text">{{
            item.title?.charAt(0) }}</v-btn>
        </template>
        <template #title>
          <v-tooltip v-if="!isShrink" location="end" :text="item.title">
            <template #activator="{ props: tooltipProps }">
              <span v-bind="tooltipProps" class="text-body-2 nav-text-overflow">{{ item.title }}</span>
            </template>
          </v-tooltip>
        </template>
      </v-list-item>
    </template>
  </v-list>
</template>

<script setup lang="ts">
import { mdiCircleSmall, mdiMenuRight } from '@mdi/js'
import { computed, watch } from 'vue'

interface MenuItem {
  title?: string
  path?: string
  icon?: string
  navigable?: boolean
  subItems?: MenuItem[]
  [key: string]: unknown
}

interface Props {
  opened?: string[]
  menuItems?: MenuItem[]
  isShrink?: boolean
}

const props = withDefaults(defineProps<Props>(), {
  opened: () => [],
  menuItems: () => [],
  isShrink: false,
})

const emit = defineEmits<{
  'update:opened': [value: string[]]
  select: [item: MenuItem]
  unshrink: []
}>()

const openedModel = computed({
  get: () => (props.isShrink ? [] : props.opened),
  set: (value) => {
    if (!props.isShrink) {
      emit('update:opened', value)
    }
  },
})

// 當側邊欄收縮時，自動收起所有展開的子選單
watch(() => props.isShrink, (newVal) => {
  if (newVal) {
    openedModel.value = []
  }
})

const isNavigable = (item: MenuItem) => item?.navigable !== false

function emitSelect (item: MenuItem) {
  // 收縮狀態下點擊選單項目時，先解除收縮再進行選擇
  // 這樣可以讓使用者看到完整的選單結構和導航結果
  if (props.isShrink) {
    emit('unshrink')
  }
  emit('select', item)
}

function getItemCount (item: MenuItem) {
  if (!item?.subItems?.length) return 0
  const countLeaf = (list: MenuItem[]): number =>
    (list || []).reduce((total: number, current: MenuItem) => {
      if (current?.subItems?.length) return total + countLeaf(current.subItems)
      return total + 1
    }, 0)
  return countLeaf(item.subItems)
}
</script>

<style scoped>
.menu-count {
  min-width: 28px;
  justify-content: center;
}

.nav-text-overflow {
  display: block;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
</style>
