import Vue from 'vue'
import routerMap from '@vue2-client/router/async/router.map'
import { mergeI18nFromRoutes } from '@vue2-client/utils/i18n'
import { arrRemoveEmpty } from '@vue2-client/utils/util'
import Router from 'vue-router'
import deepMerge from 'deepmerge'
import basicOptions from '@vue2-client/router/async/config.async'

// 应用配置
const appOptions = {
  router: undefined,
  i18n: undefined,
  store: undefined
}

/**
 * 设置应用配置
 * @param options
 */
function setAppOptions(options) {
  const { router, store, i18n } = options
  appOptions.router = router
  appOptions.store = store
  appOptions.i18n = i18n
}

// 应用路由资源
const appRouterMap = {
  routerMap: routerMap
}

/**
 * 设置应用路由资源
 * @param router 应用路由
 */
function setAppRouterMap(router) {
  appRouterMap.routerMap = Object.assign(appRouterMap.routerMap, router)
}

/**
 * 设置基础应用路由资源
 * @param router 基础路由
 */
function setBaseRouterMap(router) {
  const routes = basicOptions.routes
  for (let i = 0; i < routes.length; i++) {
    const item = router[routes[i].path]
    if (item) {
      routes[i].component = item
    }
  }
}

/**
 * 根据 路由配置 和 路由组件注册 解析路由
 * @param routesConfig 路由配置
 * @param routerMap 本地路由组件注册配置
 */
function parseRoutes(routesConfig, routerMap) {
  const routes = []
  routesConfig.forEach(item => {
    // 获取注册在 routerMap 中的 router，初始化 routeCfg
    let router
    let routeCfg = {}
    if (typeof item === 'string') {
      router = routerMap[item]
      routeCfg = { path: (router && router.path) || item, router: item }
    } else if (typeof item === 'object') {
      // 当没有设置路由对象名或者设置的是blank路由对象时, 给空界面, path为名称
      if (!item.router || item.router === 'blank') {
        router = routerMap.blank
        item.path = encodeURI(item.name)
      } else {
        router = routerMap[item.router]
        if (!router) {
          router = routerMap.blank
        }
      }
      // 查看是否是单页面
      if (item.meta && item.meta.singlePage) {
        router = routerMap.singlePage
        item.path = encodeURI(item.name)
      }
      // 查看是否是栅格配置页面
      if (item.meta && item.meta.type) {
        // 新的资源管理有单独字段存储 component
        if (item.meta.type === 'GridView' || item.component === 'GridView') {
          router = routerMap.gridView
          item.path = encodeURI(item.router) || encodeURI(item.name)
        }
      }
      // 是否是VueSfc页面
      if (item.meta && item.meta.type) {
        // 新的资源管理有单独字段存储 component
        if (item.meta.type === 'VuePage' || item.component === 'VuePage') {
          router = routerMap.vuePage
          item.path = encodeURI(item.router) || encodeURI(item.name)
        }
      }

      // 当没在动态路由对象中找到时, 不添加到路由
      // if (!router) return
      routeCfg = item
    }
    if (!router) {
      // console.warn(`can't find register for router ${routeCfg.router}, please register it in advance.`)
      router = typeof item === 'string' ? { path: item, name: item } : item
    }
    // 从 router 和 routeCfg 解析路由
    const meta = {
      authority: router.authority,
      icon: router.icon,
      page: router.page,
      link: router.link,
      params: router.params,
      query: router.query,
      ...router.meta
    }
    const cfgMeta = {
      authority: routeCfg.authority,
      icon: routeCfg.icon,
      page: routeCfg.page,
      link: routeCfg.link,
      params: routeCfg.params,
      query: routeCfg.query,
      ...routeCfg.meta
    }
    Object.keys(cfgMeta).forEach(key => {
      if (cfgMeta[key] === undefined || cfgMeta[key] === null || cfgMeta[key] === '') {
        delete cfgMeta[key]
      }
    })
    Object.assign(meta, cfgMeta)
    const route = {
      path: routeCfg.path || router.path || routeCfg.router,
      name: routeCfg.name || router.name,
      component: router.component || router,
      children: router.children,
      redirect: routeCfg.redirect || router.redirect,
      meta: { ...meta, authority: meta.authority || '*' }
    }
    if (router.beforeEnter) {
      route.beforeEnter = router.beforeEnter
    }
    if (routeCfg.invisible || router.invisible) {
      route.meta.invisible = true
    }
    if (routeCfg.children && routeCfg.children.length > 0) {
      route.children = parseRoutes(routeCfg.children, routerMap)
    }
    // 当没有子并且自己时blank(空界面)时, 不添加到路由
    if (route.component.name === 'blank' && route.children && route.children.length <= 0) return
    routes.push(route)
  })
  return routes
}

/**
 * 加载路由
 * @param routesConfig {[{router: string, children: [{router: string, children: string[]}, {router: string, children: string[]}, {router: string, authority: string, name: string, icon: string}, {path: string, router: string, name: string, icon: string, link: string}, {path: string, router: string, name: string, icon: string, link: string}]}]} 路由配置
 */
function loadRoutes(routesConfig) {
  // 兼容 0.6.1 以下版本
  /** ************* 兼容 version < v0.6.1 *****************/
  if (arguments.length > 0) {
    const arg0 = arguments[0]
    if (arg0.router || arg0.i18n || arg0.store) {
      routesConfig = arguments[1]
      console.error(
        'the usage of signature loadRoutes({router, store, i18n}, routesConfig) is out of date, please use the new signature: loadRoutes(routesConfig).'
      )
      console.error(
        '方法签名 loadRoutes({router, store, i18n}, routesConfig) 的用法已过时, 请使用新的方法签名 loadRoutes(routesConfig)。'
      )
    }
  }
  /** ************* 兼容 version < v0.6.1 *****************/

  // 应用配置
  const { router, store, i18n } = appOptions

  // 刷新页面时,有些全局状态丢失,在此处从本地缓存拿出来赋值
  if (JSON.stringify(Vue.$login.f) === '{}') {
    const login = store.getters['account/login']
    Object.assign(Vue.$login, login)
  }
  // 如果 routesConfig 有值，则更新到本地，否则从本地获取
  if (routesConfig) {
    store.commit('account/setRoutesConfig', routesConfig)
  } else {
    routesConfig = store.getters['account/routesConfig']
  }
  // 如果开启了异步路由，则加载异步路由配置
  const asyncRoutes = store.state.setting.asyncRoutes
  if (asyncRoutes) {
    if (routesConfig && routesConfig.length > 0) {
      const routes = parseRoutes(routesConfig, appRouterMap.routerMap)
      // 设置路由首页
      if (!window.__MICRO_APP_ENVIRONMENT__) {
        routes[0].redirect = store.state.setting.homePage
      }
      let finalRoutes = mergeRoutes(basicOptions.routes, routes)
      // 让顶层 * 重定向到 /404，将 404 页面挂在 root 子路由下，使其能显示左侧菜单
      const rootRoute = finalRoutes.find(r => r.path === '/')
      const top404Idx = finalRoutes.findIndex(r => r.path === '*')
      if (rootRoute && top404Idx !== -1) {
        const exp404Route = finalRoutes[top404Idx]
        // 顶层 * 改为重定向到 /404，不再直接渲染组件
        finalRoutes[top404Idx] = { path: '*', redirect: '/404', meta: { authority: '*' } }
        // /404 作为 root 子路由，在有侧边栏的布局中渲染
        if (!rootRoute.children) rootRoute.children = []
        if (!rootRoute.children.find(r => r.path === '404' || r.path === '/404')) {
          rootRoute.children.push({ ...exp404Route, path: '404' })
        }
      }
      formatRoutes(finalRoutes)
      const duplicates = checkDuplicateRouteNames(finalRoutes)
      if (duplicates.length > 0) {
        // 可以选择在这里处理重复的路由名称
        finalRoutes = deduplicateRouteNames(finalRoutes)
      }
      router.options = { ...router.options, routes: finalRoutes }
      router.matcher = new Router({ ...router.options, routes: [] }).matcher
      router.addRoutes(finalRoutes)
    }
  }
  // 提取路由国际化数据
  mergeI18nFromRoutes(i18n, router.options.routes)
  // 初始化Admin后台菜单数据
  const rootRoute = router.options.routes.find(item => item.path === '/')
  const menuRoutes = rootRoute && rootRoute.children
  if (menuRoutes) {
    store.commit('setting/setMenuData', menuRoutes)
  }
}

/**
 * 检查路由中的重复名称
 * @param {Array} routes 路由配置数组
 * @returns {Array} 重复的路由信息数组
 */
function checkDuplicateRouteNames(routes) {
  const routeMap = new Map() // 存储路由名称到路由信息的映射
  const duplicates = []

  /**
   * 递归检查路由
   * @param {Object} route 当前路由
   * @param {Array} parentPath 父级路径链
   */
  function check(route, parentPath = []) {
    if (route.name) {
      const fullPath = [...parentPath, route.path].join('/')

      if (routeMap.has(route.name)) {
        // 发现重复的路由名称
        const existing = routeMap.get(route.name)
        duplicates.push({
          name: route.name,
          newPath: fullPath,
          existingPath: existing.fullPath,
          parentPath: parentPath.join('/'),
          existingParentPath: existing.parentPath
        })
      } else {
        // 记录路由信息
        routeMap.set(route.name, {
          fullPath: fullPath,
          parentPath: parentPath.join('/'),
          route: route
        })
      }
    }

    // 递归处理子路由
    if (route.children && route.children.length > 0) {
      const currentPath = [...parentPath, route.path || '']
      route.children.forEach(child => check(child, currentPath))
    }
  }

  routes.forEach(route => check(route))
  return duplicates
}

/**
 * 处理重复的路由名称
 * @param {Array} routes 路由配置数组
 * @returns {Array} 处理后的路由数组
 */
function deduplicateRouteNames(routes) {
  const nameRegistry = new Map() // 全局名称注册表

  /**
   * 生成唯一的路由名称
   * @param {String} baseName 基础名称
   * @param {String} parentPath 父级路径
   * @returns {String} 唯一的路由名称
   */
  function generateUniqueName(baseName, parentPath) {
    // 如果父级路径存在，使用父级路径的最后一部分作为前缀
    if (parentPath && parentPath !== '/') {
      const pathParts = parentPath.split('/').filter(p => p)
      const parentName = pathParts[pathParts.length - 1] || ''
      if (parentName) {
        return `${parentName}_${baseName}`
      }
    }

    // 否则添加数字后缀
    let counter = 1
    let newName = baseName
    while (nameRegistry.has(newName)) {
      counter++
      newName = `${baseName}_${counter}`
    }
    return newName
  }

  /**
   * 递归处理路由
   * @param {Object} route 当前路由
   * @param {Array} parentPath 父级路径链
   * @param {Boolean} isRoot 是否为根级路由
   * @returns {Object|null} 处理后的路由或null
   */
  function processRoute(route, parentPath = [], isRoot = false) {
    if (!route) return null

    // 复制路由对象，避免修改原始数据
    const processedRoute = { ...route }
    const fullPath = [...parentPath, route.path || ''].filter(p => p).join('/')

    // 处理路由名称
    if (processedRoute.name) {
      const routeKey = `${processedRoute.name}::${fullPath}`

      // 检查是否已经处理过完全相同的路由（名称和路径都相同）
      if (nameRegistry.has(routeKey)) {
        // 完全重复的路由，直接跳过
        return null
      }

      // 检查名称是否已被使用
      if (nameRegistry.has(processedRoute.name)) {
        const existingRoute = nameRegistry.get(processedRoute.name)
        // 如果路径不同，说明是不同位置的同名路由，需要重命名
        if (existingRoute.fullPath !== fullPath) {
          const parentPathStr = parentPath.join('/')
          const newName = generateUniqueName(processedRoute.name, parentPathStr)
          processedRoute.name = newName
        }
      }

      // 注册当前路由
      nameRegistry.set(processedRoute.name, { fullPath, route: processedRoute })
      nameRegistry.set(routeKey, { fullPath, route: processedRoute })
    }

    // 递归处理子路由
    if (processedRoute.children && processedRoute.children.length > 0) {
      const currentPath = [...parentPath, route.path || ''].filter(p => p)
      processedRoute.children = processedRoute.children
        .map(child => processRoute(child, currentPath, false))
        .filter(child => child !== null)

      // 如果所有子路由都被过滤掉了，考虑是否保留父路由
      if (processedRoute.children.length === 0 && !isRoot) {
        // 如果是空的 blank 路由，可以移除
        if (processedRoute.component && processedRoute.component.name === 'blank') {
          return null
        }
      }
    }

    return processedRoute
  }

  // 处理所有路由
  const processedRoutes = routes.map(route => processRoute(route, [], true)).filter(route => route !== null)

  return processedRoutes
}

/**
 * 合并路由
 * @param target {Route[]}
 * @param source {Route[]}
 * @returns {Route[]}
 */
function mergeRoutes(target, source) {
  const routesMap = {}
  // eslint-disable-next-line no-return-assign
  target.forEach(item => (routesMap[item.path] = item))
  // eslint-disable-next-line no-return-assign
  source.forEach(item => (routesMap[item.path] = item))
  return Object.values(routesMap)
}

/**
 * 深度合并路由
 * @param target {Route[]}
 * @param source {Route[]}
 * @returns {Route[]}
 */
function deepMergeRoutes(target, source) {
  // 映射路由数组
  const mapRoutes = routes => {
    const routesMap = {}
    routes.forEach(item => {
      routesMap[item.path] = {
        ...item,
        children: item.children ? mapRoutes(item.children) : undefined
      }
    })
    return routesMap
  }
  const tarMap = mapRoutes(target)
  const srcMap = mapRoutes(source)

  // 合并路由
  const merge = deepMerge(tarMap, srcMap)

  // 转换为 routes 数组
  const parseRoutesMap = routesMap => {
    return Object.values(routesMap).map(item => {
      if (item.children) {
        item.children = parseRoutesMap(item.children)
      } else {
        delete item.children
      }
      return item
    })
  }
  return parseRoutesMap(merge)
}

/**
 * 格式化路由
 * @param routes 路由配置
 */
function formatRoutes(routes) {
  routes.forEach(route => {
    const { path } = route
    if (!path.startsWith('/') && path !== '*') {
      route.path = '/' + path
    }
  })
  formatAuthority(routes)
}

/**
 * 格式化路由的权限配置
 * @param routes 路由
 * @param pAuthorities 父级路由权限配置集合
 */
function formatAuthority(routes, pAuthorities = []) {
  routes.forEach(route => {
    const meta = route.meta
    const defaultAuthority = pAuthorities[pAuthorities.length - 1] || { permission: '*' }
    if (meta) {
      let authority = {}
      if (!meta.authority) {
        authority = defaultAuthority
      } else if (typeof meta.authority === 'string' || Array.isArray(meta.authority)) {
        authority.permission = meta.authority
      } else if (typeof meta.authority === 'object') {
        authority = meta.authority
        const { role } = authority
        if (typeof role === 'string') {
          authority.role = [role]
        }
        if (!authority.permission && !authority.role) {
          authority = defaultAuthority
        }
      }
      meta.authority = authority
    } else {
      const authority = defaultAuthority
      route.meta = { authority }
    }
    route.meta.pAuthorities = pAuthorities
    if (route.children) {
      formatAuthority(route.children, [...pAuthorities, route.meta.authority])
    }
  })
}

/**
 * 从路由 path 解析 i18n key
 * @param path
 * @returns {*}
 */
function getI18nKey(path) {
  const keys = path.split('/').filter(item => !item.startsWith(':') && item !== '')
  keys.push('name')
  return keys.join('.')
}

/**
 * 加载导航守卫
 * @param guards
 * @param options
 */
function loadGuards(guards, options) {
  const { beforeEach, afterEach } = guards
  const { router } = options
  beforeEach.forEach(guard => {
    if (guard && typeof guard === 'function') {
      router.beforeEach((to, from, next) => guard(to, from, next, options))
    }
  })
  afterEach.forEach(guard => {
    if (guard && typeof guard === 'function') {
      router.afterEach((to, from) => guard(to, from, options))
    }
  })
}

/**
 * 资源服务路由转新路由
 * @param func
 */
function funcToRouter(func) {
  const parsedfunc = parsefunc(func)
  return [
    {
      router: 'root',
      children: window.__MICRO_APP_ENVIRONMENT__ ? flattenTree(parsedfunc) : positionRouter(parsedfunc)
    }
  ]
}

function parsefunc(func) {
  const tree = []
  for (const row of func) {
    const route = {
      router: row.link,
      meta: {
        singlePage: row.navigate
      },
      position: row.position - 1,
      icon: row.icon,
      name: row.name
    }
    if (row.link) {
      // 旧的资源管理 link 格式为 {name_space}${link} 所以这么判断
      if (row.link.includes('$')) {
        route.router = row.link.split('$')[1]
        route.params = row.link.split('$')[0]
      }
      if (route.router.includes('?')) {
        // 把问号后面的都删了
        const [url, queryString] = route.router.split('?')
        route.router = url
        try {
          const params = new URLSearchParams(queryString)
          for (const [key, value] of params.entries()) {
            // 转换字符串布尔值为实际的布尔值
            if (value === 'true') {
              route.meta[key] = true
            } else if (value === 'false') {
              route.meta[key] = false
            } else {
              route.meta[key] = value
            }
          }
          if (route.meta.path) {
            route.path = route.meta.path
            delete route.meta.path
          }
        } catch (e) {}
      }
      if (row.configName) {
        route.meta.configName = row.configName
      }
      if (row.component) {
        route.meta.type = row.component
      }
    }
    if (row.extend && row.extend.length > 0) {
      row.extend.forEach(item => {
        if (item.key && item.value !== undefined) {
          route.meta[item.key] = item.value
        }
      })
    }
    if (row.children && row.children.length > 0) {
      route.children = parsefunc(row.children)
    }
    tree.push(route)
  }
  return tree
}

function flattenTree(tree) {
  let flat = []
  for (const node of tree) {
    const { children, ...rest } = node
    flat.push(rest)
    if (children && children.length > 0) {
      flat = flat.concat(flattenTree(children))
    }
  }
  return flat
}

/**
 * 资源服务路由排序
 */
function positionRouter(r) {
  let router = r.sort((a, b) => a.position - b.position)
  router = arrRemoveEmpty(router)
  return router
}

function funcToRouterOA(func) {
  return [
    {
      router: 'root',
      children: positionRouterOA(parsefuncOA(func))
    }
  ]
}

function positionRouterOA(r) {
  let router = []
  for (const row of r) {
    router[row.position] = row
  }
  router = arrRemoveEmpty(router)
  return router
}

function parsefuncOA(func) {
  const router = []
  for (const row of func) {
    // ？？？？？？？？
    if (row.navigate === 'innerOAView') {
      row.link = 'innerOAView'
      delete row.navigate
    }
    const route = {
      router: row.link,
      meta: {
        singlePage: row.navigate
      },
      position: row.position - 1,
      icon: row.icon,
      name: row.name
    }
    if (row.link) {
      if (route.router.includes('?')) {
        // 把问号后面的都删了
        const [url, queryString] = route.router.split('?')
        route.router = url
        try {
          const params = new URLSearchParams(queryString)
          for (const [key, value] of params.entries()) {
            // 转换字符串布尔值为实际的布尔值
            if (value === 'true') {
              route.meta[key] = true
            } else if (value === 'false') {
              route.meta[key] = false
            } else {
              route.meta[key] = value
            }
          }
          if (route.meta.path) {
            route.path = route.meta.path
            delete route.meta.path
          }
        } catch (e) {}
      }
    }
    if (row.children && row.children.length > 0) {
      route.children = parsefunc(row.children)
    }
    router.push(route)
  }
  return router
}

export {
  parseRoutes,
  loadRoutes,
  formatAuthority,
  getI18nKey,
  loadGuards,
  deepMergeRoutes,
  formatRoutes,
  setAppOptions,
  funcToRouter,
  setAppRouterMap,
  setBaseRouterMap,
  funcToRouterOA
}
