<script lang="ts" setup>
import type { ComputedRef, Ref } from 'vue';
import { computed, inject, onMounted, ref, watch } from 'vue';
import { Icon } from '@iconify/vue';
import { useThrottleFn, useWindowSize } from '@vueuse/core';
import { configKey, handleMenuClickKey, menusKey, routeKey, routerKey, themeColorKey } from '../../../utils/injectedKeys';
import type { AntMenu, LayoutConfig, ThemeColor } from '../types';

const { width } = useWindowSize();
const { router } = inject<{ router: Ref<any> }>(routerKey)!;
const { route } = inject<{ route: ComputedRef<Record<string, any>> }>(routeKey)!;
const { config } = inject<{ config: Ref<LayoutConfig> }>(configKey)!;
const { themeColor } = inject<{ themeColor: Ref<ThemeColor> }>(themeColorKey)!;
const { handleMenuClick } = inject<{ handleMenuClick: (value: any) => void }>(handleMenuClickKey)!;
const menus = inject<Ref<AntMenu[]>>(menusKey)!;

const headerNavMenuRef = ref<HTMLDivElement | null>(null);

const menuActiveColor = computed(() => themeColor.value.menuActiveColor || themeColor.value.primary);

const appsIconWidth = 35;
// 计算所有一级菜单的宽度总和
const menuItemWidthSum = computed(() => {
  const itemWidths = Array.from(headerNavMenuRef.value?.children || []).map(el => {
    return el.clientWidth;
  });
  if (itemWidths.length) {
    return itemWidths.reduce((a, b) => a + b) + appsIconWidth;
  }
  return appsIconWidth;
});
const hiddenMenuList = ref<AntMenu[]>([]);
const calcShowMenuList = (menuList: AntMenu[]) => {
  const totalWidth = headerNavMenuRef.value?.clientWidth;
  // 只需要第一层，使用浅拷贝
  const originMenus = menuList.filter(menu => !menu.meta?.isHidden);
  if (totalWidth && totalWidth <= menuItemWidthSum.value) {
    const count = +((menuItemWidthSum.value - totalWidth) / 160).toFixed(0) + 1;
    hiddenMenuList.value = originMenus.slice(originMenus.length - count, originMenus.length);
    return originMenus.slice(0, originMenus.length - count);
  }
  hiddenMenuList.value = [];
  return originMenus;
};
const showMenuList = ref<AntMenu[]>(calcShowMenuList(menus.value));

watch(
  () => [width.value, menus.value],
  useThrottleFn(() => {
    showMenuList.value = calcShowMenuList(menus.value);
  }, 300)
);

onMounted(() => {
  showMenuList.value = calcShowMenuList(menus.value);
});

const onMenuClick = (menu: AntMenu) => {
  handleMenuClick({ menu });
  if (menu.children?.length) {
    const headerNavMenu = findFirstMenu(menu.children);
    router.value.push(headerNavMenu.key);
  } else {
    router.value.push(menu.key);
  }
};

const isActive = computed(() => {
  return (key: string) => {
    if (route.value.path.startsWith(key)) {
      const flag = (route.value.path as string).replace(key, '');
      return flag.startsWith('/') || flag === '';
    }
    if (route.value.path.startsWith(`/${key}`)) {
      const flag = (route.value.path as string).replace(`/${key}`, '');
      return flag.startsWith('/') || flag === '';
    }
    return false;
  };
});
const isHiddenMenuActive = computed(() => hiddenMenuList.value.some(i => isActive.value(i.key || '')));
const findFirstMenu = (menuList: AntMenu[]): AntMenu => {
  if (!menuList[0].children?.length) return menuList[0];
  return findFirstMenu(menuList[0].children);
};
</script>

<template>
  <div ref="headerNavMenuRef" class="headerNavMenu">
    <template v-for="menu in showMenuList" :key="menu.key">
      <slot
        name="headerMenuItemRender"
        :menu="menu"
        :isActive="isActive(menu.key!)"
        :onClick="() => onMenuClick(menu)"
      >
        <div class="headerNavMenu-item" @click="onMenuClick(menu)">
          <div
            class="headerNavMenu-item-wrapper"
            :class="{
              'headerNavMenu-item-wrapper-flat': config.menuStyle === 'flat',
              'headerNavMenu-item-active': isActive(menu.key!),
              'headerNavMenu-item-wrapper-light': config.navStyle === 'light'
            }"
          >
            <Icon v-if="typeof menu.meta?.icon === 'string' && config.isHeaderMenuIcon" :icon="menu.meta?.icon" />
            <component :is="menu.meta?.icon()" v-if="typeof menu.meta?.icon === 'function' && config.isHeaderMenuIcon" />
            <span style="white-space: nowrap">{{ menu.label }}</span>
          </div>
        </div>
      </slot>
    </template>
    <a-dropdown trigger="hover">
      <div
        v-if="hiddenMenuList.length"
        class="headerNavMenu-eclipsed"
        :class="{ 'headerNavMenu-eclipsed-active': isHiddenMenuActive }"
      >
        <Icon icon="carbon:list" />
      </div>
      <template #overlay>
        <a-menu>
          <a-menu-item
            v-for="menu in hiddenMenuList"
            :key="menu.key"
            :class="{ 'headerNavMenu-item-active': isActive(menu.key!) }"
            @click="onMenuClick(menu)"
          >
            <Icon
              v-if="menu.meta?.icon"
              :color="isActive(menu.key!) ? themeColor.primary : 'inherit'"
              :icon="menu.meta.icon as any"
            />
            <span
              :style="{
                whiteSpace: 'nowrap',
                marginLeft: '8px',
                color: isActive(menu.key!) ? themeColor.primary : 'inherit'
              }"
            >
              {{ menu.label }}
            </span>
          </a-menu-item>
        </a-menu>
      </template>
    </a-dropdown>
  </div>
</template>

<style scoped>
.headerNavMenu-eclipsed-active {
  background-color: v-bind("menuActiveColor");
}

:deep(.ant-dropdown-menu-item) > .ant-dropdown-menu-title-content {
  display: flex;
  align-items: center;
}

.headerNavMenu {
  position: relative;
  width: 100%;
  height: 46px;
  display: flex;
  align-items: center;
  margin-left: 8px;
}
.headerNavMenu-eclipsed {
  position: relative;
  height: 100%;
  width: 30px;
  margin: 0 8px;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
  transition: all 0.2s ease 0s;
}
.headerNavMenu-eclipsed:after {
  content: "";
  position: absolute;
  transition: all 0.2s ease 0s;
}
.headerNavMenu-apps {
  cursor: pointer;
  margin: 0 8px;
  color: v-bind("menuActiveColor");
}
.headerNavMenu-apps:hover {
  color: v-bind("menuActiveColor");
}
.headerNavMenu-item {
  height: 100%;
  max-width: 160px;
  display: flex;
  align-items: center;
  cursor: pointer;
  color: inherit;
}
.headerNavMenu-item-wrapper {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  padding: 0 12px;
  color: inherit;
  background-color: transparent;
}
.headerNavMenu-item-wrapper-light {
  color: inherit;
  background-color: inherit;
}
.headerNavMenu-item-wrapper span {
  white-space: nowrap;
  margin-left: 4px;
  max-width: 210px;
  text-overflow: ellipsis;
  overflow: hidden;
}
.headerNavMenu-item-wrapper:hover {
  background-color: v-bind("menuActiveColor");
  color: whitesmoke;
}

.headerNavMenu-item-active {
  color: whitesmoke !important;
  background-color: v-bind("menuActiveColor") !important;
}
</style>
