import type { Router, RouteLocationNormalized, NavigationGuardNext } from 'vue-router'
import NProgress from 'nprogress'
import { useSettingStore } from '@/store/modules/setting'
import { useUserStore } from '@/store/modules/user'
import { useMenuStore } from '@/store/modules/menu'
import { setWorktab } from '@/utils/navigation'
import { setPageTitle, setSystemTheme } from '../utils/utils'
import { registerDynamicRoutes } from '../utils/registerRoutes'
import { AppRouteRecord } from '@/types/router'
import { RoutesAlias } from '../routesAlias'
import { menuDataToRouter } from '../utils/menuToRouter'
import { asyncRoutes } from '../routes/asyncRoutes'
import { loadingService } from '@/utils/ui'
import { useCommon } from '@/composables/useCommon'
import { useWorktabStore } from '@/store/modules/worktab'
import { isInWhiteList, hasRoutePermission, isTokenValid, buildLoginRedirect } from './permission'

// 是否已注册动态路由
const isRouteRegistered = ref(false)

// 临时开发模式：跳过所有权限验证（开发静态页面时使用）
const DEV_MODE_SKIP_AUTH = false

/**
 * 路由全局前置守卫
 * 处理进度条、获取菜单列表、动态路由注册、404 检查、工作标签页及页面标题设置
 */
export function setupBeforeEachGuard(router: Router): void {
  router.beforeEach(
    async (
      to: RouteLocationNormalized,
      from: RouteLocationNormalized,
      next: NavigationGuardNext
    ) => {
      try {
        // 开发模式：直接放行，无需登录
        if (DEV_MODE_SKIP_AUTH) {
          const settingStore = useSettingStore()
          if (settingStore.showNprogress) {
            NProgress.start()
          }
          setSystemTheme(to)
          setPageTitle(to)

          // 开发模式下，首次访问时注册所有路由
          if (!isRouteRegistered.value) {
            const menuList = asyncRoutes.map((route) => menuDataToRouter(route))
            const menuStore = useMenuStore()
            menuStore.setMenuList(menuList)
            registerDynamicRoutes(router, menuList)
            isRouteRegistered.value = true

            // 重新导航到目标路由
            next({ path: to.path, query: to.query, hash: to.hash, replace: true })
            return
          }

          // 设置工作标签页
          setWorktab(to)
          next()
          return
        }

        await handleRouteGuard(to, from, next, router)
      } catch (error) {
        console.error('路由守卫处理失败:', error)
        next('/exception/500')
      }
    }
  )
}

/**
 * 处理路由守卫逻辑
 */
async function handleRouteGuard(
  to: RouteLocationNormalized,
  from: RouteLocationNormalized,
  next: NavigationGuardNext,
  router: Router
): Promise<void> {
  const settingStore = useSettingStore()
  const userStore = useUserStore()

  // 处理进度条
  if (settingStore.showNprogress) {
    NProgress.start()
  }

  // 设置系统主题
  setSystemTheme(to)

  // 处理登录状态
  if (!(await handleLoginStatus(to, userStore, next))) {
    return
  }

  // 处理动态路由注册
  if (!isRouteRegistered.value && userStore.isLogin) {
    await handleDynamicRoutes(to, router, next)
    return
  }

  // 处理已知的匹配路由
  if (to.matched.length > 0) {
    setWorktab(to)
    setPageTitle(to)
    next()
    return
  }

  // 路由未匹配时，判断是 404 还是 403
  if (userStore.isLogin) {
    // 检查路由是否存在于 asyncRoutes 中
    const routeExistsInAsync = checkRouteExistsInAsyncRoutes(to.path, asyncRoutes)
    console.log(`[路由检查] 目标路径: ${to.path}, 是否存在于asyncRoutes: ${routeExistsInAsync}`)

    if (routeExistsInAsync) {
      // 路由存在于 asyncRoutes 但未注册，说明用户没有权限
      console.warn('路由存在但用户无权限访问:', to.path)
      next(RoutesAlias.Exception403 || '/exception/403')
      return
    }
  }

  // 路由不存在，跳转到 404
  console.log(`[路由检查] 路径 ${to.path} 不存在于asyncRoutes，跳转404`)
  next(RoutesAlias.Exception404)
}

/**
 * 处理登录状态
 */
async function handleLoginStatus(
  to: RouteLocationNormalized,
  userStore: ReturnType<typeof useUserStore>,
  next: NavigationGuardNext
): Promise<boolean> {
  const { isLogin, accessToken, info } = userStore

  // 如果访问的是白名单路由，直接放行
  if (isInWhiteList(to.path) || to.meta.noLogin) {
    // 如果已登录且访问登录页，重定向到首页
    if (isLogin && to.path === RoutesAlias.Login) {
      next(RoutesAlias.Home || '/')
      return false
    }
    return true
  }

  // 检查是否已登录
  if (!isLogin || !accessToken) {
    userStore.logOut()
    next(buildLoginRedirect(to.fullPath))
    return false
  }

  // 检查 Token 是否有效
  if (!isTokenValid(accessToken)) {
    console.warn('Token 已过期，需要重新登录')
    userStore.logOut()
    next(buildLoginRedirect(to.fullPath))
    return false
  }

  // 检查页面级权限
  if (!hasRoutePermission(to, info)) {
    console.warn('无权限访问该页面:', to.path)
    next(RoutesAlias.Exception403 || '/exception/403')
    return false
  }

  return true
}

/**
 * 处理动态路由注册
 */
async function handleDynamicRoutes(
  to: RouteLocationNormalized,
  router: Router,
  next: NavigationGuardNext
): Promise<void> {
  try {
    await getMenuData(router)
    next({
      path: to.path,
      query: to.query,
      hash: to.hash,
      replace: true
    })
  } catch (error) {
    console.error('动态路由注册失败:', error)
    next('/exception/500')
  }
}

/**
 * 获取菜单数据
 * @param router 路由实例
 */
async function getMenuData(router: Router): Promise<void> {
  try {
    if (useCommon().isFrontendMode.value) {
      await processFrontendMenu(router) // 前端控制模式
    } else {
      await processBackendMenu(router) // 后端控制模式
    }
  } catch (error) {
    handleMenuError(error)
  }
}

/**
 * 处理前端控制模式的菜单逻辑
 */
async function processFrontendMenu(router: Router): Promise<void> {
  const closeLoading = loadingService.showLoading()

  try {
    const menuList = asyncRoutes.map((route) => menuDataToRouter(route))
    const userStore = useUserStore()
    const roles = userStore.info.roles

    if (!roles || roles.length === 0) {
      console.warn('用户角色信息不存在，清除登录状态')
      closeLoading()
      userStore.logOut()
      throw new Error('获取用户角色失败')
    }

    const filteredMenuList = filterMenuByRoles(menuList, roles)
    await new Promise((resolve) => setTimeout(resolve, 300))
    await registerAndStoreMenu(router, filteredMenuList, closeLoading)
  } catch (error) {
    closeLoading()
    throw error
  }
}

/**
 * 处理后端控制模式的菜单
 */
async function processBackendMenu(router: Router): Promise<void> {
  const closeLoading = loadingService.showLoading()

  try {
    const userStore = useUserStore()

    // 如果是超级管理员（user_type === 1），直接使用所有 asyncRoutes
    if (userStore.isSuperAdmin) {
      const menuList = asyncRoutes.map((route) => menuDataToRouter(route))
      await registerAndStoreMenu(router, menuList, closeLoading)
      return
    }

    // 普通用户：使用后端返回的菜单
    const backendMenus = userStore.menus || []
    const routeMap = buildRouteMap(asyncRoutes)

    const menuList = backendMenus
      .map((menu) => convertBackendMenuToRoute(menu, routeMap))
      .filter((route) => route !== null)

    const finalMenuList = mergeDefaultMenus(menuList, routeMap)
    await registerAndStoreMenu(router, finalMenuList, closeLoading)
  } catch (error) {
    closeLoading()
    throw error
  }
}

/**
 * 合并默认菜单
 * 将配置的默认菜单合并到后端返回的菜单中
 * 注意: /dashboard 及其子路由(console/analysis/ecommerce)不再作为默认菜单强制显示
 * 这些路由只有在后端 menus 中返回时才会显示
 */
function mergeDefaultMenus(
  backendMenus: AppRouteRecord[],
  routeMap: Map<string, AppRouteRecord>
): AppRouteRecord[] {
  // 移除 /dashboard 作为默认菜单，现在仪表台路由完全由后端控制
  const defaultMenuPaths: string[] = []

  const defaultMenus: AppRouteRecord[] = defaultMenuPaths
    .map((path) => {
      const route = routeMap.get(path)
      return route ? menuDataToRouter(route) : null
    })
    .filter((menu): menu is AppRouteRecord => menu !== null)

  const backendPaths = new Set(backendMenus.map((m) => m.path))
  const filteredDefaultMenus = defaultMenus.filter((m) => !backendPaths.has(m.path))

  return [...filteredDefaultMenus, ...backendMenus]
}

/**
 * 构建 URL 到路由的映射表
 */
function buildRouteMap(routes: AppRouteRecord[], parentPath = ''): Map<string, AppRouteRecord> {
  const map = new Map<string, AppRouteRecord>()

  routes.forEach((route) => {
    // 构建完整路径
    const fullPath = route.path.startsWith('/')
      ? route.path
      : parentPath
        ? `${parentPath}/${route.path}`.replace(/\/+/g, '/')
        : `/${route.path}`

    // 存储路由映射
    map.set(fullPath, route)

    // 递归处理子路由
    if (route.children && route.children.length > 0) {
      const childMap = buildRouteMap(route.children, fullPath)
      childMap.forEach((childRoute, childPath) => {
        map.set(childPath, childRoute)
      })
    }
  })

  return map
}

/**
 * 将后端菜单数据转换为路由格式
 * 递归处理所有层级的 children
 */
function convertBackendMenuToRoute(
  menu: any,
  routeMap: Map<string, AppRouteRecord>
): AppRouteRecord | null {
  const menuUrl = menu.url || '/'
  const matchedRoute = routeMap.get(menuUrl)

  if (!matchedRoute) {
    console.warn(`未找到与菜单 URL "${menuUrl}" 匹配的路由定义: ${menu.name}`)

    // 如果当前菜单没有匹配的路由，但有 children，尝试递归处理 children
    if (menu.children && menu.children.length > 0) {
      const children = menu.children
        .map((child: any) => convertBackendMenuToRoute(child, routeMap))
        .filter((child: AppRouteRecord | null) => child !== null)

      // 如果子菜单有有效的路由，返回一个包含子菜单的占位路由
      if (children.length > 0) {
        return {
          path: menuUrl,
          name: menu.name || menuUrl.replace(/\//g, '_'),
          meta: {
            title: menu.name,
            permission: menu.perm_code,
            sort: menu.sort || 0,
            icon: menu.icon,
            isHide: false,
            roles: undefined,
            permissions: undefined
          },
          children: children
        } as AppRouteRecord
      }
    }

    return null
  }

  const route: AppRouteRecord = {
    path: menuUrl,
    name: matchedRoute.name,
    component: matchedRoute.component,
    meta: {
      ...matchedRoute.meta,
      title: menu.name,
      permission: menu.perm_code,
      sort: menu.sort || matchedRoute.meta?.sort || 0,
      icon: menu.icon || matchedRoute.meta?.icon,
      // 清除前端定义的 roles 和 permissions，使用后端权限控制
      roles: undefined,
      permissions: undefined
    }
  }

  // 递归处理后端返回的 children
  if (menu.children && menu.children.length > 0) {
    const children = menu.children
      .map((child: any) => convertBackendMenuToRoute(child, routeMap))
      .filter((child: AppRouteRecord | null) => child !== null)

    if (children.length > 0) {
      route.children = children
    }
  }

  return route
}

/**
 * 注册路由并存储菜单数据
 */
async function registerAndStoreMenu(
  router: Router,
  menuList: AppRouteRecord[],
  closeLoading: () => void
): Promise<void> {
  if (!isValidMenuList(menuList)) {
    closeLoading()
    throw new Error('获取菜单列表失败，请重新登录')
  }

  const menuStore = useMenuStore()
  menuStore.setMenuList(menuList)
  registerDynamicRoutes(router, menuList)
  isRouteRegistered.value = true

  const worktabStore = useWorktabStore()
  worktabStore.validateWorktabs(router)

  // 刷新后只保留固定标签页和当前标签页
  worktabStore.initializeAfterRefresh()

  closeLoading()
}

/**
 * 处理菜单相关错误
 */
function handleMenuError(error: unknown): void {
  console.error('菜单处理失败:', error)
  // 确保 loading 被关闭
  loadingService.hideLoading()
  useUserStore().logOut()
  throw error instanceof Error ? error : new Error('获取菜单列表失败，请重新登录')
}

/**
 * 根据角色过滤菜单
 */
const filterMenuByRoles = (menu: AppRouteRecord[], roles: string[]): AppRouteRecord[] => {
  return menu.reduce((acc: AppRouteRecord[], item) => {
    const itemRoles = item.meta?.roles
    const hasPermission = !itemRoles || itemRoles.some((role) => roles?.includes(role))

    if (hasPermission) {
      const filteredItem = { ...item }
      if (filteredItem.children?.length) {
        filteredItem.children = filterMenuByRoles(filteredItem.children, roles)
      }
      acc.push(filteredItem)
    }

    return acc
  }, [])
}

/**
 * 验证菜单列表是否有效
 */
function isValidMenuList(menuList: AppRouteRecord[]): boolean {
  return Array.isArray(menuList) && menuList.length > 0
}

/**
 * 检查路由是否存在于 asyncRoutes 中
 * 支持动态参数匹配，如 /account-management/enterprise-customer/customer-accounts/3000 匹配 enterprise-customer/customer-accounts/:id
 * @param targetPath 目标路由路径，如 /account-management/enterprise-customer/customer-accounts/3000
 * @param routes 路由配置数组
 * @param parentPath 父路由路径
 */
function checkRouteExistsInAsyncRoutes(
  targetPath: string,
  routes: AppRouteRecord[],
  parentPath = ''
): boolean {
  for (const route of routes) {
    // 构建完整路径
    const fullPath = route.path.startsWith('/')
      ? route.path
      : parentPath
        ? `${parentPath}/${route.path}`.replace(/\/+/g, '/')
        : `/${route.path}`

    // 检查当前路由是否匹配（支持动态参数）
    const isMatch = matchRoutePath(targetPath, fullPath)

    if (isMatch) {
      console.log(`[路由匹配成功] 目标: ${targetPath}, 匹配到: ${fullPath}`)
      return true
    }

    // 递归检查子路由
    if (route.children && route.children.length > 0) {
      if (checkRouteExistsInAsyncRoutes(targetPath, route.children, fullPath)) {
        return true
      }
    }
  }

  return false
}

/**
 * 匹配路由路径，支持动态参数
 * @param targetPath 实际路径，如 /account-management/enterprise-customer/customer-accounts/3000
 * @param routePath 路由定义路径，如 /account-management/enterprise-customer/customer-accounts/:id
 */
function matchRoutePath(targetPath: string, routePath: string): boolean {
  // 移除查询参数
  const cleanTargetPath = targetPath.split('?')[0]
  const cleanRoutePath = routePath.split('?')[0]

  // 如果完全匹配，直接返回
  if (cleanTargetPath === cleanRoutePath) {
    return true
  }

  // 将路径分割成段
  const targetSegments = cleanTargetPath.split('/').filter(Boolean)
  const routeSegments = cleanRoutePath.split('/').filter(Boolean)

  // 段数必须相同
  if (targetSegments.length !== routeSegments.length) {
    return false
  }

  // 逐段比较
  for (let i = 0; i < routeSegments.length; i++) {
    const routeSegment = routeSegments[i]
    const targetSegment = targetSegments[i]

    // 如果是动态参数（以 : 开头），跳过比较
    if (routeSegment.startsWith(':')) {
      continue
    }

    // 如果不是动态参数，必须完全匹配
    if (routeSegment !== targetSegment) {
      return false
    }
  }

  return true
}

/**
 * 重置路由相关状态
 */
export function resetRouterState(router: Router): void {
  isRouteRegistered.value = false
  // 清理动态注册的路由
  router.getRoutes().forEach((route) => {
    if (route.meta?.dynamic) {
      router.removeRoute(route.name as string)
    }
  })
  // 清空菜单数据
  const menuStore = useMenuStore()
  menuStore.setMenuList([])
}
