/**
 * 认证工具测试
 */

import { describe, it, expect, beforeEach } from 'vitest'
import { authManager, UserRole, Permission } from '../auth'
import { createMockUser } from '@/test/utils'

describe('authManager', () => {
  beforeEach(() => {
    // 清理本地存储
    localStorage.clear()
    sessionStorage.clear()
  })

  describe('用户认证状态', () => {
    it('应该正确检查未登录状态', () => {
      expect(authManager.isAuthenticated()).toBe(false)
      expect(authManager.getCurrentUser()).toBeNull()
      expect(authManager.getAccessToken()).toBeNull()
    })

    it('应该正确设置和获取用户信息', () => {
      const mockUser = createMockUser({ role: 'admin' })
      const mockToken = 'mock.jwt.token'

      authManager.setCurrentUser(mockUser)
      authManager.setAccessToken(mockToken)

      expect(authManager.isAuthenticated()).toBe(true)
      expect(authManager.getCurrentUser()).toEqual(mockUser)
      expect(authManager.getAccessToken()).toBe(mockToken)
    })

    it('应该正确清除认证信息', () => {
      const mockUser = createMockUser()
      const mockToken = 'mock.jwt.token'
      const mockRefreshToken = 'mock.refresh.token'

      authManager.setCurrentUser(mockUser)
      authManager.setAccessToken(mockToken)
      authManager.setRefreshToken(mockRefreshToken)

      expect(authManager.isAuthenticated()).toBe(true)

      authManager.clearAuth()

      expect(authManager.isAuthenticated()).toBe(false)
      expect(authManager.getCurrentUser()).toBeNull()
      expect(authManager.getAccessToken()).toBeNull()
      expect(authManager.getRefreshToken()).toBeNull()
    })
  })

  describe('角色检查', () => {
    it('应该正确识别管理员角色', () => {
      const adminUser = createMockUser({ role: UserRole.ADMIN })
      authManager.setCurrentUser(adminUser)

      expect(authManager.getUserRole()).toBe(UserRole.ADMIN)
      expect(authManager.hasRole(UserRole.ADMIN)).toBe(true)
      expect(authManager.isAdmin()).toBe(true)
      expect(authManager.isManager()).toBe(false)
      expect(authManager.isTrainee()).toBe(false)
    })

    it('应该正确识别管理者角色', () => {
      const managerUser = createMockUser({ role: UserRole.MANAGER })
      authManager.setCurrentUser(managerUser)

      expect(authManager.getUserRole()).toBe(UserRole.MANAGER)
      expect(authManager.hasRole(UserRole.MANAGER)).toBe(true)
      expect(authManager.isAdmin()).toBe(false)
      expect(authManager.isManager()).toBe(true)
      expect(authManager.isTrainee()).toBe(false)
    })

    it('应该正确识别学员角色', () => {
      const traineeUser = createMockUser({ role: UserRole.TRAINEE })
      authManager.setCurrentUser(traineeUser)

      expect(authManager.getUserRole()).toBe(UserRole.TRAINEE)
      expect(authManager.hasRole(UserRole.TRAINEE)).toBe(true)
      expect(authManager.isAdmin()).toBe(false)
      expect(authManager.isManager()).toBe(false)
      expect(authManager.isTrainee()).toBe(true)
    })
  })

  describe('权限检查', () => {
    it('管理员应该拥有所有权限', () => {
      const adminUser = createMockUser({ role: UserRole.ADMIN })
      authManager.setCurrentUser(adminUser)

      expect(authManager.hasPermission(Permission.USER_CREATE)).toBe(true)
      expect(authManager.hasPermission(Permission.COURSE_DELETE)).toBe(true)
      expect(authManager.hasPermission(Permission.SYSTEM_CONFIG)).toBe(true)
      expect(authManager.hasAllPermissions([
        Permission.USER_VIEW,
        Permission.COURSE_MANAGE,
        Permission.SYSTEM_LOG
      ])).toBe(true)
    })

    it('管理者应该拥有部分权限', () => {
      const managerUser = createMockUser({ role: UserRole.MANAGER })
      authManager.setCurrentUser(managerUser)

      expect(authManager.hasPermission(Permission.USER_VIEW)).toBe(true)
      expect(authManager.hasPermission(Permission.COURSE_CREATE)).toBe(true)
      expect(authManager.hasPermission(Permission.TEAM_MANAGE)).toBe(true)
      expect(authManager.hasPermission(Permission.SYSTEM_CONFIG)).toBe(false)
      expect(authManager.hasPermission(Permission.USER_DELETE)).toBe(false)
    })

    it('学员应该只有基础权限', () => {
      const traineeUser = createMockUser({ role: UserRole.TRAINEE })
      authManager.setCurrentUser(traineeUser)

      expect(authManager.hasPermission(Permission.COURSE_VIEW)).toBe(true)
      expect(authManager.hasPermission(Permission.EXAM_VIEW)).toBe(true)
      expect(authManager.hasPermission(Permission.TRAINING_VIEW)).toBe(true)
      expect(authManager.hasPermission(Permission.COURSE_CREATE)).toBe(false)
      expect(authManager.hasPermission(Permission.USER_MANAGE)).toBe(false)
      expect(authManager.hasPermission(Permission.SYSTEM_CONFIG)).toBe(false)
    })

    it('应该正确检查多个权限', () => {
      const managerUser = createMockUser({ role: UserRole.MANAGER })
      authManager.setCurrentUser(managerUser)

      expect(authManager.hasAnyPermission([
        Permission.USER_DELETE,
        Permission.COURSE_VIEW
      ])).toBe(true)

      expect(authManager.hasAllPermissions([
        Permission.COURSE_VIEW,
        Permission.TEAM_VIEW
      ])).toBe(true)

      expect(authManager.hasAllPermissions([
        Permission.COURSE_VIEW,
        Permission.SYSTEM_CONFIG
      ])).toBe(false)
    })
  })

  describe('路由权限', () => {
    it('公共路由应该允许所有用户访问', () => {
      expect(authManager.canAccessRoute('/login')).toBe(true)
      expect(authManager.canAccessRoute('/register')).toBe(true)
      expect(authManager.canAccessRoute('/404')).toBe(true)
    })

    it('需要登录的路由应该拒绝未登录用户', () => {
      expect(authManager.canAccessRoute('/dashboard')).toBe(false)
      expect(authManager.canAccessRoute('/trainee/course-center')).toBe(false)
      expect(authManager.canAccessRoute('/admin/dashboard')).toBe(false)
    })

    it('管理员路由应该只允许管理员访问', () => {
      const adminUser = createMockUser({ role: UserRole.ADMIN })
      const managerUser = createMockUser({ role: UserRole.MANAGER })
      const traineeUser = createMockUser({ role: UserRole.TRAINEE })

      authManager.setCurrentUser(adminUser)
      authManager.setAccessToken('mock.token')
      expect(authManager.canAccessRoute('/admin/dashboard')).toBe(true)

      authManager.setCurrentUser(managerUser)
      expect(authManager.canAccessRoute('/admin/dashboard')).toBe(false)

      authManager.setCurrentUser(traineeUser)
      expect(authManager.canAccessRoute('/admin/dashboard')).toBe(false)
    })

    it('管理者路由应该允许管理员和管理者访问', () => {
      const adminUser = createMockUser({ role: UserRole.ADMIN })
      const managerUser = createMockUser({ role: UserRole.MANAGER })
      const traineeUser = createMockUser({ role: UserRole.TRAINEE })

      authManager.setCurrentUser(adminUser)
      authManager.setAccessToken('mock.token')
      expect(authManager.canAccessRoute('/manager/team-dashboard')).toBe(true)

      authManager.setCurrentUser(managerUser)
      expect(authManager.canAccessRoute('/manager/team-dashboard')).toBe(true)

      authManager.setCurrentUser(traineeUser)
      expect(authManager.canAccessRoute('/manager/team-dashboard')).toBe(false)
    })
  })

  describe('默认路由', () => {
    it('应该根据用户角色返回正确的默认路由', () => {
      const adminUser = createMockUser({ role: UserRole.ADMIN })
      authManager.setCurrentUser(adminUser)
      expect(authManager.getDefaultRoute()).toBe('/admin/dashboard')

      const managerUser = createMockUser({ role: UserRole.MANAGER })
      authManager.setCurrentUser(managerUser)
      expect(authManager.getDefaultRoute()).toBe('/manager/team-dashboard')

      const traineeUser = createMockUser({ role: UserRole.TRAINEE })
      authManager.setCurrentUser(traineeUser)
      expect(authManager.getDefaultRoute()).toBe('/trainee/course-center')

      authManager.clearAuth()
      expect(authManager.getDefaultRoute()).toBe('/dashboard')
    })
  })

  describe('Token 过期检查', () => {
    it('应该正确检查过期的 token', () => {
      // 创建一个已过期的 JWT token (过期时间为过去)
      const expiredPayload = { exp: Math.floor(Date.now() / 1000) - 3600 } // 1小时前过期
      const expiredToken = `header.${btoa(JSON.stringify(expiredPayload))}.signature`
      
      authManager.setAccessToken(expiredToken)
      expect(authManager.isTokenExpired()).toBe(true)
    })

    it('应该正确检查有效的 token', () => {
      // 创建一个未过期的 JWT token (过期时间为未来)
      const validPayload = { exp: Math.floor(Date.now() / 1000) + 3600 } // 1小时后过期
      const validToken = `header.${btoa(JSON.stringify(validPayload))}.signature`
      
      authManager.setAccessToken(validToken)
      expect(authManager.isTokenExpired()).toBe(false)
    })

    it('应该将无效格式的 token 视为过期', () => {
      authManager.setAccessToken('invalid.token')
      expect(authManager.isTokenExpired()).toBe(true)
    })

    it('应该将空 token 视为过期', () => {
      expect(authManager.isTokenExpired()).toBe(true)
    })
  })
})
