<script setup lang="ts">
import type { CSSProperties } from 'vue'
import type { RouteLocationNormalized } from 'vue-router/auto'
import Logo from '../logo/index.vue'
import SiderTrigger from '../trigger/sider-trigger.vue'
import MixSubMenu from './mix-sub-menu.vue'
import { createNamespace, listenerRouteChange } from '~/utils'
import { MixSidebarTriggerEnum, NavBarModeEnum } from '~/constants'

const props = defineProps({
  mixSidebarWidth: { type: Number, default: 40 },
})

const title = import.meta.env.VITE_APP_TITLE

const { t } = useI18n()
const { bem } = createNamespace('layout-mix-menu')
const { currentRoute } = useRouter()
const go = useGo()
let currentRouteRef = $ref<Nullable<RouteLocationNormalized>>(null)
let menuModulesRef = $ref<Menu[]>([])
let activePathRef = $ref<string>('')
let childrenMenus = $ref<Menu[]>([])
let openMenu = $ref(false)
let childrenTitle = $ref('')
const sideRef = ref<ElRef>(null)

const {
  getIsFixed,
  getIsMixSidebar,
  getMixSideFixed,
  getMixSideTrigger,
  getCloseMixSidebarOnChange,
  getMenuWidth,
  getCollapsed,
  getMenuType,
  mixSideHasChildren,
  setMenuSetting,
} = useMenuSetting()

const {
  getChildrenMenus,
  getCurrentParentPath,
  getShallowMenus,
} = useMenu()

let oldIsFixed = unref(getIsFixed)
let pushpin = unref(getIsFixed)

onMounted(async () => {
  menuModulesRef = await getShallowMenus()
  activePathRef = await getCurrentParentPath(currentRoute.value.path)
  const currentItem = menuModulesRef.find(item => item.path === activePathRef)
  if (currentItem) {
    handleModuleClick(currentItem.path, false, currentItem.meta?.title || '')
  }
})

listenerRouteChange(async (route) => {
  currentRouteRef = route
  activePathRef = await getCurrentParentPath(route.path)
  setActive(true)
  if (unref(getCloseMixSidebarOnChange)) {
    closeMenu()
  }
})

// Set the currently active menu and submenu
async function setActive(setChildren = false) {
  const path = currentRouteRef?.path
  if (!path) {
    return
  }
  //   activePathRef = await getCurrentParentPath(path)
  if (unref(getIsMixSidebar)) {
    const activeMenu = unref(menuModulesRef).find(item => item.path === unref(activePathRef))
    const p = activeMenu?.path
    if (p) {
      const children = await getChildrenMenus(p)
      if (setChildren) {
        childrenMenus = children

        if (unref(getMixSideFixed)) {
          openMenu = children.length > 0
        }
      }
      if (children.length === 0) {
        childrenMenus = []
      }
    }
  }
  mixSideHasChildren.value = childrenMenus.length > 0
}

function closeMenu() {
  if (!unref(getIsFixed)) {
    openMenu = false
    setActive(false)
  }
}

// Process module menu click
async function handleModuleClick(path: string, hover = false, title = '') {
  const children = await getChildrenMenus(path)
  childrenTitle = t(title)
  if (unref(activePathRef) === path) {
    if (!hover) {
      if (!unref(openMenu)) {
        openMenu = true
      }
      else {
        closeMenu()
      }
    }
    else {
      if (!unref(openMenu)) {
        openMenu = true
      }
    }
    if (!unref(openMenu)) {
      await setActive()
    }
  }
  else {
    openMenu = true
    activePathRef = path
  }

  if (!children || children.length === 0) {
    if (!hover) {
      go(path)
    }
    childrenMenus = []
    closeMenu()
    return
  }
  childrenMenus = children
  mixSideHasChildren.value = childrenMenus.length > 0
}

function getItemEvents(item: Menu) {
  if (unref(getMixSideTrigger) === MixSidebarTriggerEnum.HOVER) {
    return {
      onMouseenter: () => {
        return handleModuleClick(item.path, true, item.meta?.title || '')
      },
      onClick: async () => {
        const children = await getChildrenMenus(item.path)
        if (item.path && (!children || children.length === 0)) {
          go(item.path)
        }
      },
    }
  }
  return {
    onClick: () => {
      handleModuleClick(item.path, false, item.meta?.title || '')
    },
  }
}

const getMenuEventsRef = computed(() => {
  return !unref(getMixSideFixed)
    ? {
        onMouseleave: () => {
          // 鼠标移出菜单不做操作
          // if (!openMenu.value) {
          //   setActive(true)
          // }
          // 鼠标离开Menu 不触发关闭菜单面板
          // closeMenu()
        },
        onMouseenter: () => {
        },
      }
    : {}
})

function handleFixedMenu() {
  setMenuSetting({
    mixSideFixed: !unref(getMixSideFixed),
  })
  pushpin = !unref(getMixSideFixed)
}

const getMenuStyle = computed((): CSSProperties => {
  if (unref(getIsFixed)) {
    setActive(true)
  }
  else {
    if (oldIsFixed !== unref(getIsFixed) && !pushpin) {
      closeMenu()
    }
    else {
      pushpin = false
    }
  }
  oldIsFixed = unref(getIsFixed)
  return {
    width: unref(openMenu) ? `${unref(getMenuWidth)}px` : 0,
    left: `${props.mixSidebarWidth}px`,
  }
})
</script>

<template>
  <div :class="bem()">
    <Logo
      v-if="getMenuType === NavBarModeEnum.MIX_SIDEBAR"
      class="shadow"
      :class="[bem('logo')]"
      :style="{ '--un-shadow-color': 'var(--n-border-color)' }"
      :show-title="false"
    />
    <NScrollbar
      :class="bem('scrollbar')"
      v-bind="getMenuEventsRef"
    >
      <ul :class="bem('module')">
        <li
          v-for="item in menuModulesRef"
          :key="item.path"
          :class="[
            bem('module__item'),
            {
              [bem('module__item--active') as string]: item.path === activePathRef,
            },
          ]"
          v-bind="getItemEvents(item)"
        >
          <LIcon
            :class="bem('module__icon')"
            :size="getCollapsed ? 16 : 20"
            :icon="item.icon || (item.meta && item.meta.icon)"
          />
          <p v-show="!getCollapsed" :class="bem('module__name')">
            {{ $t(item.meta?.title || '') }}
          </p>
        </li>
      </ul>
    </NScrollbar>
    <SiderTrigger />
    <div
      ref="sideRef"
      class="shadow"
      :class="[bem('menu-list')]"
      :style="getMenuStyle"
      @mouseleave="closeMenu"
    >
      <div
        v-show="openMenu && childrenMenus.length > 0"
        class="shadow"
        :class="[
          bem('menu-list__title'),
          {
            show: openMenu,
          },
        ]"
      >
        <span class="text">{{ title }}</span>
        <LIcon
          :size="16"
          :icon="getMixSideFixed ? 'ant-design:pushpin-filled' : 'ant-design:pushpin-outlined'"
          class="pushpin hover:cursor-pointer"
          @click="handleFixedMenu"
        />
      </div>
      <NH5
        v-if="openMenu"
        class="mb-2!"
        :class="bem('menu-list__children-title')"
        :style="{ '--n-text-color': 'var(--n-text-color)' }"
        prefix="bar"
        strong
      >
        {{ childrenTitle }}
      </NH5>
      <MixSubMenu :list="childrenMenus" />
    </div>
  </div>
</template>

<style lang="less" scoped>
.layout-mix-menu {
  display: flex;
  flex-direction: column;
  height: 100%;

  &__logo {
    flex-shrink: 0;
    justify-content: center;
  }

  &__scrollbar {
    flex: 1;
    flex-basis: auto;
  }
  &__module {
    position: relative;
    padding: 1px 0 40px 0;
    margin: 0;
    &__item {
      position: relative;
      padding: 12px 0;
      display: flex;
      justify-content: center;
      align-items: center;
      flex-direction: column;
      cursor: pointer;
      transition: all 0.3s ease;

      &:hover,
      &--active {
        // font-weight: 700;

        color: #18a058;
        &::before {
          position: absolute;
          top: 0;
          left: 0;
          width: 3px;
          height: 100%;
          background-color: #18a058;
          content: '';
        }
      }
    }
    &__icon {
      transition: all 0.3s;
    }

    &__name {
      margin-bottom: 0;
      margin-top: 5px;
      font-size: 12px;
      transition: all 0.3s;
    }
  }
  &__menu-list {
    position: fixed;
    height: 100%;
    top: 0;
    width: 0px;
    height: calc(100%);
    background-color: var(--n-color);
    transition: all 0.3s;

    &__title {
      display: flex;
      height: 48px;
      font-size: 18px;
      opacity: 0%;
      transition: unset;
      align-items: center;
      justify-content: space-between;
      box-sizing: border-box;
      padding-left: 20px;

      &.show {
        min-width: 130px;
        opacity: 100%;
        transition: all 0.5s ease;
      }
      .pushpin {
        margin-right: 8px;
      }
    }
    &__children-title {
      padding: 6px 20px;
      margin: 0;
    }
  }
}
</style>
