import type { ElegantConstRoute, LastLevelRouteKey, RouteKey, RouteMap } from '@elegant-router/types'
import type { RouteLocationNormalizedLoaded, RouteRecordRaw } from 'vue-router'
import { useSvgIcon } from '@/hooks/common/icon'
import { $t } from '@/locales'

/**
 * 根据角色过滤权限路由
 *
 * @param routes 权限路由
 * @param roles 角色
 */
export function filterAuthRoutesByRoles(routes: ElegantConstRoute[], roles: string[]) {
  return routes.flatMap(route => filterAuthRouteByRoles(route, roles))
}

/**
 * 根据角色过滤权限路由
 *
 * @param route 权限路由
 * @param roles 角色
 */
function filterAuthRouteByRoles(route: ElegantConstRoute, roles: string[]): ElegantConstRoute[] {
  const routeRoles = (route.meta && route.meta.roles) || []

  // 如果路由的 "roles" 为空，则允许访问
  const isEmptyRoles = !routeRoles.length

  // 如果用户的角色包含在路由的 "roles" 中，则允许访问
  const hasPermission = routeRoles.some(role => roles.includes(role))

  const filterRoute = { ...route }

  if (filterRoute.children?.length) {
    filterRoute.children = filterRoute.children.flatMap(item => filterAuthRouteByRoles(item, roles))
  }

  // 如果过滤后没有子路由，则排除该路由
  if (filterRoute.children?.length === 0) {
    return []
  }

  return hasPermission || isEmptyRoles ? [filterRoute] : []
}

/**
 * 根据 order 对路由进行排序
 *
 * @param route 路由
 */
function sortRouteByOrder(route: ElegantConstRoute) {
  if (route.children?.length) {
    route.children.sort((next, prev) => (Number(next.meta?.order) || 0) - (Number(prev.meta?.order) || 0))
    route.children.forEach(sortRouteByOrder)
  }

  return route
}

/**
 * 根据 order 对路由进行排序
 *
 * @param routes 路由
 */
export function sortRoutesByOrder(routes: ElegantConstRoute[]) {
  routes.sort((next, prev) => (Number(next.meta?.order) || 0) - (Number(prev.meta?.order) || 0))
  routes.forEach(sortRouteByOrder)

  return routes
}

/**
 * 根据权限路由获取全局菜单
 * 当嵌套路由里面，有且仅有一个子路由时，将其提升到一级菜单，点击一级菜单时，跳转到子路由
 * @param routes 权限路由
 * @param shouldHoist 是否提升
 * @param includeHidden 是否包含隐藏路由
 */
export function getGlobalMenusByAuthRoutes(routes: ElegantConstRoute[], shouldHoist = false, includeHidden = false) {
  const menus: App.Global.Menu[] = []

  routes.forEach((route) => {
    if (includeHidden || !route.meta?.hideInMenu) {
      const menu = getGlobalMenuByBaseRoute(route)

      if (route.children?.some(child => includeHidden || !child.meta?.hideInMenu)) {
        menu.children = getGlobalMenusByAuthRoutes(route.children, shouldHoist, includeHidden)
      }

      // 如果只有一个子菜单，将其提升
      if (shouldHoist && menu.children?.length === 1) {
        const singleChild = menu.children[0]
        menu.key = singleChild.key
        menu.routeKey = singleChild.routeKey
        menu.routePath = singleChild.routePath
        menu.children = singleChild.children
      }

      menus.push(menu)
    }
  })

  return menus
}

/**
 * 更新全局菜单的国际化
 *
 * @param menus
 */
export function updateLocaleOfGlobalMenus(menus: App.Global.Menu[]) {
  const result: App.Global.Menu[] = []

  menus.forEach((menu) => {
    const { i18nKey, label, children } = menu

    const newLabel = i18nKey ? $t(i18nKey) : label

    const newMenu: App.Global.Menu = {
      ...menu,
      label: newLabel,
    }

    if (children?.length) {
      newMenu.children = updateLocaleOfGlobalMenus(children)
    }

    result.push(newMenu)
  })

  return result
}

/**
 * 根据路由获取全局菜单
 *
 * @param route
 */
function getGlobalMenuByBaseRoute(route: RouteLocationNormalizedLoaded | ElegantConstRoute) {
  const { SvgIconVNode } = useSvgIcon()

  const { name, path } = route
  const { title, i18nKey, icon = import.meta.env.VITE_MENU_ICON, localIcon, iconFontSize } = route.meta ?? {}

  const label = i18nKey ? $t(i18nKey) : title!

  const menu: App.Global.Menu = {
    key: name as string,
    label,
    i18nKey,
    routeKey: name as RouteKey,
    routePath: path as RouteMap[RouteKey],
    icon: SvgIconVNode({ icon, localIcon, fontSize: iconFontSize || 20 }),
  }

  return menu
}

/**
 * 获取缓存路由名称
 *
 * @param routes Vue 路由 (两级)
 */
export function getCacheRouteNames(routes: RouteRecordRaw[]) {
  const cacheNames: LastLevelRouteKey[] = []

  routes.forEach((route) => {
    // 只获取最后两级有组件的路由
    route.children?.forEach((child) => {
      if (child.component && child.meta?.keepAlive) {
        cacheNames.push(child.name as LastLevelRouteKey)
      }
    })
  })

  return cacheNames
}

/**
 * 根据路由名称判断路由是否存在
 *
 * @param routeName
 * @param routes
 */
export function isRouteExistByRouteName(routeName: RouteKey, routes: ElegantConstRoute[]) {
  return routes.some(route => recursiveGetIsRouteExistByRouteName(route, routeName))
}

/**
 * 递归判断路由名称是否存在
 *
 * @param route
 * @param routeName
 */
function recursiveGetIsRouteExistByRouteName(route: ElegantConstRoute, routeName: RouteKey) {
  let isExist = route.name === routeName

  if (isExist) {
    return true
  }

  if (route.children && route.children.length) {
    isExist = route.children.some(item => recursiveGetIsRouteExistByRouteName(item, routeName))
  }

  return isExist
}

/**
 * 获取选中的菜单 key 路径
 *
 * @param selectedKey
 * @param menus
 */
export function getSelectedMenuKeyPathByKey(selectedKey: string, menus: App.Global.Menu[]) {
  const keyPath: string[] = []

  menus.some((menu) => {
    const path = findMenuPath(selectedKey, menu)

    const find = Boolean(path?.length)

    if (find) {
      keyPath.push(...path!)
    }

    return find
  })

  return keyPath
}

/**
 * 查找菜单路径
 *
 * @param targetKey 目标菜单 key
 * @param menu 菜单
 */
function findMenuPath(targetKey: string, menu: App.Global.Menu): string[] | null {
  const path: string[] = []

  function dfs(item: App.Global.Menu): boolean {
    path.push(item.key)

    if (item.key === targetKey) {
      return true
    }

    if (item.children) {
      for (const child of item.children) {
        if (dfs(child)) {
          return true
        }
      }
    }

    path.pop()

    return false
  }

  if (dfs(menu)) {
    return path
  }

  return null
}

/**
 * 将菜单转换为面包屑
 *
 * @param menu
 */
function transformMenuToBreadcrumb(menu: App.Global.Menu) {
  const { children, ...rest } = menu

  const breadcrumb: App.Global.Breadcrumb = {
    ...rest,
  }

  if (children?.length) {
    breadcrumb.options = children.map(transformMenuToBreadcrumb)
  }

  return breadcrumb
}

/**
 * 根据路由获取面包屑
 *
 * @param route
 * @param menus
 */
export function getBreadcrumbsByRoute(
  route: RouteLocationNormalizedLoaded,
  menus: App.Global.Menu[],
): App.Global.Breadcrumb[] {
  const key = route.name as string
  const activeKey = route.meta?.activeMenu

  for (const menu of menus) {
    if (menu.key === key) {
      return [transformMenuToBreadcrumb(menu)]
    }

    if (menu.key === activeKey) {
      const ROUTE_DEGREE_SPLITTER = '_'

      const parentKey = key.split(ROUTE_DEGREE_SPLITTER).slice(0, -1).join(ROUTE_DEGREE_SPLITTER)

      const breadcrumbMenu = getGlobalMenuByBaseRoute(route)
      if (parentKey !== activeKey) {
        return [transformMenuToBreadcrumb(breadcrumbMenu)]
      }

      return [transformMenuToBreadcrumb(menu), transformMenuToBreadcrumb(breadcrumbMenu)]
    }

    if (menu.children?.length) {
      const result = getBreadcrumbsByRoute(route, menu.children)
      if (result.length > 0) {
        return [transformMenuToBreadcrumb(menu), ...result]
      }
    }
  }

  return []
}

/**
 * 将菜单转换为搜索菜单
 *
 * @param menus - 菜单
 * @param treeMap
 */
export function transformMenuToSearchMenus(menus: App.Global.Menu[], treeMap: App.Global.Menu[] = []) {
  if (menus && menus.length === 0)
    return []
  return menus.reduce((acc, cur) => {
    if (!cur.children) {
      acc.push(cur)
    }
    if (cur.children && cur.children.length > 0) {
      transformMenuToSearchMenus(cur.children, treeMap)
    }
    return acc
  }, treeMap)
}
