import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router'
import Layout from '@/views/index.vue'
import { getStore } from '@/utils/storage'
import { isArray } from '@/utils/validate'
import { usePermissionStore } from '@/stores'
import type { RouterItem } from '@/utils/crypto'

// Pre-register all view components for dynamic routing
const viewModules = import.meta.glob('@views/**/*.vue')

const whiteListRouterMap: RouteRecordRaw[] = [
  {
    name: 'login',
    path: '/login',
    meta: { name: '登陆' },
    component: () => import('@views/login/Login.vue')
  },
  {
    name: 'update-pwd',
    path: '/update-pwd',
    meta: { name: '修改密码' },
    component: () => import('@views/login/UpdatePwd.vue')
  },
  {
    name: '404',
    path: '/404',
    meta: { name: '404错误' },
    component: () => import('@views/error/404.vue')
  }
]

export const noMenuRouterMap: RouteRecordRaw[] = [
  {
    name: 'Home',
    path: '/home',
    meta: { name: '首页', icon: 'el-icon-s-home', keepAlive: true },
    component: () => import('@views/home.vue')
  }
]

export const constantRouterMap: RouteRecordRaw[] = [
  {
    name: 'Main',
    path: '/',
    meta: { name: '应用' },
    redirect: '/home',
    component: Layout,
    children: []
  },
  ...whiteListRouterMap
]

const router = createRouter({
  history: createWebHistory('/admin/'),
  routes: constantRouterMap
})

const createRouterFn = () => {
  return createRouter({
    history: createWebHistory('/admin/'),
    routes: constantRouterMap
  })
}

export function resetRouter() {
  const newRouter = createRouterFn()
  ;(router as any).matcher = (newRouter as any).matcher
}

const whiteList = whiteListRouterMap.map((menu) => menu.path)

let routesLoaded = false

router.beforeEach(async (to, _from, next) => {
  const token = getStore('accessToken')

  if (token) {
    if (to.path === '/login') {
      next()
      return
    }
    if (!routesLoaded) {
      try {
        const permStore = usePermissionStore()
        const accessedRoutes = await permStore.generateRoutes()
        accessedRoutes.forEach((item: any) => {
          router.addRoute('Main', item)
        })
        routesLoaded = true
        next({ ...to, replace: true })
      } catch {
        next('/login')
      }
      return
    }
    if (to.matched.length === 0) {
      next('/404')
    }
    next()
  } else {
    if (whiteList.indexOf(to.path) !== -1) {
      next()
    } else {
      next({ name: 'login' })
    }
  }
})

export default router

export function filterAsyncRoutes(asyncRouter: any[] | null, parentPath: string): RouterItem[] {
  const accessedRoutes: RouterItem[] = []
  if (asyncRouter != null) {
    asyncRouter.forEach((myRouter) => {
      const path = parentPath + '/' + myRouter.path
      const treeRouter: RouterItem = {
        name: myRouter.path,
        path,
        id: myRouter.id,
        meta: {
          name: myRouter.title,
          icon: myRouter.icon,
          keepAlive: myRouter.keepAlive === '1',
          hidden: myRouter.hidden === '1'
        },
        component: undefined,
        children: undefined
      }
      if (myRouter.component) {
        if (myRouter.component === 'layout') {
          treeRouter.component = Layout
        } else if (myRouter.component === 'subLayout') {
          treeRouter.component = () => import('@views/layout/Layout.vue')
        } else {
          // Case-insensitive lookup matching backend component path to filesystem
          const targetLower = myRouter.component.toLowerCase()
          const matchedKey = Object.keys(viewModules).find(k => {
            const keyLower = k.toLowerCase()
            return keyLower.endsWith(`/views/${targetLower}.vue`) || keyLower.endsWith(`/views/${targetLower}/index.vue`)
          })
          if (matchedKey) {
            treeRouter.component = viewModules[matchedKey]
          }
        }
      }
      let children = myRouter.children
      if (children && isArray(children)) {
        children = filterAsyncRoutes(children, path)
      }
      treeRouter.children = children
      accessedRoutes.push(treeRouter)
    })
  }
  return accessedRoutes
}
