import type { Router } from 'vue-router'

import { HOME_PATH, LOGIN_PATH, PATHS } from '@vben/constants'
import { preferences } from '@vben/preferences'
import { useAccessStore } from '@vben/stores'
import { startProgress, stopProgress } from '@vben/utils'

import { accessRoutes, coreRouteNames } from '#/router/routes'
import hud from '#/utils/hud'

import { generateAccess } from './access'

/**
 * 通用守卫配置
 * @param router
 */
const setupCommonGuard = (router: Router) => {
  // 记录已经加载的页面
  const loadedPaths = new Set<string>()

  router.beforeEach((to) => {
    to.meta.loaded = loadedPaths.has(to.path)

    // 页面加载进度条
    if (!to.meta.loaded && preferences.transition.progress) {
      startProgress()
    }
    return true
  })

  router.afterEach((to) => {
    // 记录页面是否加载,如果已经加载，后续的页面切换动画等效果不在重复执行
    loadedPaths.add(to.path)

    // 关闭页面加载进度条
    if (preferences.transition.progress) {
      stopProgress()
    }
  })
}

/**
 * 权限访问守卫配置
 * @param router
 */
const setupAccessGuard = (router: Router) => {
  router.beforeEach(async (to, from) => {
    const accessStore = useAccessStore()

    // 生成路由表
    // 基本路由，这些路由不需要进入权限拦截
    if (coreRouteNames.includes(to.name as string)) {
      if (to.path === LOGIN_PATH && accessStore.accessToken) {
        return decodeURIComponent(
          (to.query?.redirect as string) || PATHS.homePath,
        )
      }
      return true
    }

    // accessToken 检查
    if (!accessStore.accessToken) {
      // 明确声明忽略权限访问权限，则可以访问
      if (to.meta.ignoreAccess) {
        return true
      }

      // 没有访问权限，跳转登录页面
      if (to.fullPath !== LOGIN_PATH) {
        return {
          path: LOGIN_PATH,
          // 如不需要，直接删除 query
          query:
            to.fullPath === PATHS.homePath
              ? {}
              : { redirect: encodeURIComponent(to.fullPath) },
          // 携带当前跳转的页面，登录后重新跳转该页面
          replace: true,
        }
      }
      return to
    }

    // 是否已经生成过动态路由
    if (accessStore.isAccessChecked) {
      return true
    }

    if (from.path !== PATHS.loginPath) {
      // 登录那里已经获取到了用户信息，这里不需要再次获取
      const authStore = useAuthStore()
      // 当前登录用户拥有的角色标识列表
      await authStore.fetchUserInfo()
    }

    // 生成菜单和路由
    const { accessibleMenus, accessibleRoutes } = await generateAccess({
      roles: [],
      router,
      // 则会在菜单中显示，但是访问会被重定向到403
      routes: accessRoutes,
    })

    // 保存菜单信息和路由信息
    accessStore.setAccessMenus(accessibleMenus)
    accessStore.setAccessRoutes(accessibleRoutes)
    accessStore.setIsAccessChecked(true)
    let redirectPath: string
    if (from.query.redirect) {
      redirectPath = from.query.redirect as string
    } else if (to.path === PATHS.homePath || to.path === HOME_PATH) {
      redirectPath = PATHS.homePath
    } else {
      redirectPath = to.fullPath
    }
    return {
      ...router.resolve(decodeURIComponent(redirectPath)),
      replace: true,
    }
  })
}

/**
 * 项目守卫配置
 * @param router
 */
const createRouterGuard = (router: Router) => {
  /** 通用 */
  setupCommonGuard(router)
  /** 权限访问 */
  setupAccessGuard(router)

  router.onError((error) => {
    // 关闭全局弹框
    hud.hide()
    hud.hideToast()
    if (error.message.includes('Failed to fetch dynamically imported module')) {
      hud.alert({
        title: '提示',
        content: '发现新版本，请刷新页面',
        onConfirm: () => {
          window.location.reload()
        },
      })
    }
  })
}

export { createRouterGuard }
