/**
 * @description 路由守卫和权限检查
 * @author yslg
 * @since 2025-10-07
 */

import type { Router, NavigationGuardNext, RouteLocationNormalized } from 'vue-router';
import type { Store } from 'vuex';
import { AuthState } from '@/store/modules/auth';

/**
 * 白名单路由 - 无需登录即可访问
 */
const WHITE_LIST = [
  '/login',
  '/register', 
  '/forgot-password',
  '/home',
  '/403',
  '/404',  // 404页面允许访问（但未登录时不会被路由到这里）
  '/500'
];

/**
 * 设置路由守卫
 * @param router Vue Router实例
 * @param store Vuex Store实例
 */
export function setupRouterGuards(router: Router, store: Store<any>) {
  
  // 全局前置守卫
  router.beforeEach(async (to, from, next) => {
    // 开始页面加载进度条
    startProgress();
    
    try {
      await handleRouteGuard(to, from, next, store);
    } catch (error) {
      console.error('路由守卫执行失败:', error);
      // 发生错误时跳转到500页面
      next('/500');
    }
  });
  
  // 全局后置钩子

  router.afterEach((to) => {
    // 结束页面加载进度条
    finishProgress();
    
    // 设置页面标题
    setPageTitle(to.meta?.title as string);
  });
  
  // 全局解析守卫（在导航被确认之前，同时在所有组件内守卫和异步路由组件被解析之后调用）
  router.beforeResolve(async (to, from, next) => {
    // 这里可以处理一些最终的权限检查或数据预加载
    next();
  });
}

/**
 * 处理路由守卫逻辑
 */
async function handleRouteGuard(
  to: RouteLocationNormalized,
  from: RouteLocationNormalized, 
  next: NavigationGuardNext,
  store: Store<any>
) {
  const authState: AuthState = store.state.auth;
  const isAuthenticated = store.getters['auth/isAuthenticated'];
  
  // 检查是否在白名单中
  if (isInWhiteList(to.path)) {
    return next();
  }
  
  // 检查用户是否已登录
  if (!isAuthenticated) {
    // 未登录，重定向到登录页
    return next({
      path: '/login',
      query: { 
        redirect: to.fullPath // 记录用户想要访问的页面
      }
    });
  }
  
  // 用户已登录，检查是否需要生成动态路由
  // 注意：通常情况下路由应该在 main.ts 初始化时就已经生成
  // 这里主要处理登录后首次生成路由的情况
  if (!authState.routesLoaded && authState.menus && authState.menus.length > 0) {
    try {
      console.log('[路由守卫] 路由未加载，开始生成动态路由');
      // 生成动态路由
      await store.dispatch('auth/generateRoutes');
      
      console.log('[路由守卫] 动态路由生成成功，重新导航');
      // 重新导航到目标路由
      return next({ ...to, replace: true });
    } catch (error) {
      console.error('[路由守卫] 生成动态路由失败:', error);
      // 清除认证信息并跳转到登录页
      store.commit('auth/CLEAR_AUTH');
      return next('/login');
    }
  }
  
  // 检查页面权限
  const hasPermission = await checkPagePermission(to, store);
  if (!hasPermission) {
    // 无权限访问，跳转到403页面
    return next('/403');
  }
  
  // 所有检查通过，继续导航
  next();
}

/**
 * 检查路径是否在白名单中
 */
function isInWhiteList(path: string): boolean {
  return WHITE_LIST.some(whitePath => {
    if (whitePath.endsWith('*')) {
      // 支持通配符匹配
      const prefix = whitePath.slice(0, -1);
      return path.startsWith(prefix);
    }
    return path === whitePath;
  });
}

/**
 * 检查页面权限
 */
async function checkPagePermission(
  route: RouteLocationNormalized,
  store: Store<any>
): Promise<boolean> {
  // 如果路由元信息中没有要求权限，则允许访问
  if (route.meta?.requiresAuth === false) {
    return true;
  }
  
  // 检查路由是否需要特定权限
  const requiredPermissions = route.meta?.permissions as string[] | undefined;
  
  if (!requiredPermissions || requiredPermissions.length === 0) {
    // 无特定权限要求，但需要登录，已经在前面检查过登录状态
    return true;
  }
  
  // 检查用户是否有所需权限
  const hasPermission = store.getters['auth/hasAnyPermission'];
  return hasPermission(requiredPermissions);
}

/**
 * 设置页面标题
 */
function setPageTitle(title?: string) {
  const appTitle = '校园新闻管理系统';
  document.title = title ? `${title} - ${appTitle}` : appTitle;
}

/**
 * 开始进度条（可以集成 NProgress 或其他进度条库）
 */
function startProgress() {
  // TODO: 集成进度条库，如 NProgress
  // NProgress.start();
}

/**
 * 完成进度条
 */
function finishProgress() {
  // TODO: 集成进度条库，如 NProgress
  // NProgress.done();
}

/**
 * Token自动刷新中间件
 */
export function setupTokenRefresh(store: Store<any>) {
  // 设置定时器自动刷新Token
  setInterval(async () => {
    const authState: AuthState = store.state.auth;
    
    if (!authState.token || !authState.loginDomain) {
      return;
    }
    
    // 检查Token是否快要过期（例如：提前5分钟刷新）
    const tokenExpireTime = authState.loginDomain.tokenExpireTime;
    if (tokenExpireTime) {
      const expireTime = new Date(tokenExpireTime).getTime();
      const currentTime = Date.now();
      const fiveMinutes = 5 * 60 * 1000;
      
      if (expireTime - currentTime <= fiveMinutes) {
        try {
          await store.dispatch('auth/refreshToken');
          console.log('Token自动刷新成功');
        } catch (error) {
          console.error('Token自动刷新失败:', error);
        }
      }
    }
  }, 60 * 1000); // 每分钟检查一次
}

/**
 * 权限检查工具函数
 */
export class PermissionChecker {
  private store: Store<any>;
  
  constructor(store: Store<any>) {
    this.store = store;
  }
  
  /**
   * 检查是否有指定权限
   */
  hasPermission(permissionCode: string): boolean {
    return this.store.getters['auth/hasPermission'](permissionCode);
  }
  
  /**
   * 检查是否有任意一个权限
   */
  hasAnyPermission(permissionCodes: string[]): boolean {
    return this.store.getters['auth/hasAnyPermission'](permissionCodes);
  }
  
  /**
   * 检查是否有所有权限
   */
  hasAllPermissions(permissionCodes: string[]): boolean {
    return this.store.getters['auth/hasAllPermissions'](permissionCodes);
  }
  
  /**
   * 检查是否有指定角色
   */
  hasRole(roleCode: string): boolean {
    const userRoles = this.store.getters['auth/userRoles'];
    return userRoles.some((role: any) => role.code === roleCode);
  }
  
  /**
   * 检查是否有任意一个角色
   */
  hasAnyRole(roleCodes: string[]): boolean {
    return roleCodes.some(code => this.hasRole(code));
  }
}
