/**
 * 路由守卫测试文件
 */

import { RouterGuard, RouterGuardOptions } from './router';
import { Auth } from '../core/auth';
import { Storage } from '../utils/storage';

// Mock Auth类
class MockAuth {
  private _isAuthenticated = false;
  private _userInfo: any = null;
  
  isAuthenticated(): boolean {
    return this._isAuthenticated;
  }
  
  setAuthenticated(authenticated: boolean): void {
    this._isAuthenticated = authenticated;
  }
  
  getUserInfo(): any {
    return this._userInfo;
  }
  
  setUserInfo(userInfo: any): void {
    this._userInfo = userInfo;
  }
  
  async login(redirectUri?: string): Promise<void> {
    // Mock login implementation
    console.log('Mock login called with redirectUri:', redirectUri);
  }
  
  async hasPermission(permission: string | string[]): Promise<boolean> {
    if (!this._isAuthenticated || !this._userInfo) return false;
    const permissions = Array.isArray(permission) ? permission : [permission];
    const userPermissions = this._userInfo.permissions || [];
    return permissions.some(p => userPermissions.includes(p));
  }
  
  async hasAllPermissions(permissions: string[]): Promise<boolean> {
    if (!this._isAuthenticated || !this._userInfo) return false;
    const userPermissions = this._userInfo.permissions || [];
    return permissions.every(p => userPermissions.includes(p));
  }
  
  async hasRole(role: string | string[]): Promise<boolean> {
    if (!this._isAuthenticated || !this._userInfo) return false;
    const roles = Array.isArray(role) ? role : [role];
    const userRoles = this._userInfo.roles || [];
    return roles.some(r => userRoles.includes(r));
  }
  
  async hasAllRoles(roles: string[]): Promise<boolean> {
    if (!this._isAuthenticated || !this._userInfo) return false;
    const userRoles = this._userInfo.roles || [];
    return roles.every(r => userRoles.includes(r));
  }
}

describe('RouterGuard', () => {
  let routerGuard: RouterGuard;
  let mockAuth: MockAuth;
  let storage: Storage;

  beforeEach(() => {
    storage = new Storage('localStorage');
    mockAuth = new MockAuth() as any;
    routerGuard = new RouterGuard(mockAuth as unknown as Auth);
  });

  describe('构造函数', () => {
    test('应该正确初始化', () => {
      expect(routerGuard).toBeInstanceOf(RouterGuard);
    });

    test('应该在没有Auth实例时抛出错误', () => {
      expect(() => new RouterGuard(null as any)).toThrow('Auth instance is required');
    });
  });

  describe('权限检查', () => {
    test('应该允许不需要认证的路由', async () => {
      const options: RouterGuardOptions = {
        requiresAuth: false
      };
      
      const result = await routerGuard.check(options);
      expect(result.allowed).toBe(true);
      expect(result.reason).toBeUndefined();
    });

    test('应该拒绝未认证用户的访问', async () => {
      const options: RouterGuardOptions = {
        requiresAuth: true
      };
      
      const result = await routerGuard.check(options);
      expect(result.allowed).toBe(false);
      expect(result.reason).toBe('NOT_AUTHENTICATED');
    });

    test('应该允许已认证用户的访问', async () => {
      // 设置用户为已认证状态
      mockAuth.setAuthenticated(true);
      mockAuth.setUserInfo({
        permissions: ['read:user'],
        roles: ['user']
      });

      const options: RouterGuardOptions = {
        requiresAuth: true
      };
      
      const result = await routerGuard.check(options);
      expect(result.allowed).toBe(true);
    });

    test('应该检查单个权限', async () => {
      mockAuth.setAuthenticated(true);
      mockAuth.setUserInfo({
        permissions: ['read:user', 'write:user'],
        roles: ['user']
      });

      const options: RouterGuardOptions = {
        requiresAuth: true,
        requiredPermissions: ['read:user']
      };
      
      const result = await routerGuard.check(options);
      expect(result.allowed).toBe(true);
    });

    test('应该拒绝缺少权限的访问', async () => {
      mockAuth.setAuthenticated(true);
      mockAuth.setUserInfo({
        permissions: ['read:user'],
        roles: ['user']
      });

      const options: RouterGuardOptions = {
        requiresAuth: true,
        requiredPermissions: ['write:user']
      };
      
      const result = await routerGuard.check(options);
      expect(result.allowed).toBe(false);
      expect(result.reason).toBe('INSUFFICIENT_PERMISSIONS');
    });

    test('应该检查多个权限（需要全部）', async () => {
      mockAuth.setAuthenticated(true);
      mockAuth.setUserInfo({
        permissions: ['read:user', 'write:user', 'delete:user'],
        roles: ['admin']
      });

      const options: RouterGuardOptions = {
        requiresAuth: true,
        requiredPermissions: ['read:user', 'write:user'],
        requireAllPermissions: true
      };
      
      const result = await routerGuard.check(options);
      expect(result.allowed).toBe(true);
    });

    test('应该检查多个权限（需要任一）', async () => {
      mockAuth.setAuthenticated(true);
      mockAuth.setUserInfo({
        permissions: ['read:user'],
        roles: ['user']
      });

      const options: RouterGuardOptions = {
        requiresAuth: true,
        requiredPermissions: ['read:user', 'write:user'],
        requireAllPermissions: false
      };
      
      const result = await routerGuard.check(options);
      expect(result.allowed).toBe(true);
    });

    test('应该检查角色', async () => {
      mockAuth.setAuthenticated(true);
      mockAuth.setUserInfo({
        permissions: ['read:user'],
        roles: ['admin', 'user']
      });

      const options: RouterGuardOptions = {
        requiresAuth: true,
        requiredRoles: ['admin']
      };
      
      const result = await routerGuard.check(options);
      expect(result.allowed).toBe(true);
    });

    test('应该拒绝缺少角色的访问', async () => {
      mockAuth.setAuthenticated(true);
      mockAuth.setUserInfo({
        permissions: ['read:user'],
        roles: ['user']
      });

      const options: RouterGuardOptions = {
        requiresAuth: true,
        requiredRoles: ['admin']
      };
      
      const result = await routerGuard.check(options);
      expect(result.allowed).toBe(false);
      expect(result.reason).toBe('INSUFFICIENT_ROLES');
    });
  });

  describe('hasPermission方法', () => {
    beforeEach(() => {
      mockAuth.setAuthenticated(true);
      mockAuth.setUserInfo({
        permissions: ['read:user', 'write:user'],
        roles: ['user']
      });
    });

    test('应该检查单个权限', async () => {
      const result = await routerGuard.hasPermission('read:user');
      expect(result).toBe(true);
    });

    test('应该检查多个权限（需要全部）', async () => {
      const result = await routerGuard.hasPermission(['read:user', 'write:user'], true);
      expect(result).toBe(true);
    });

    test('应该检查多个权限（需要任一）', async () => {
      const result = await routerGuard.hasPermission(['read:user', 'delete:user'], false);
      expect(result).toBe(true);
    });

    test('应该在未认证时返回false', async () => {
      mockAuth.setAuthenticated(false);
      const result = await routerGuard.hasPermission('read:user');
      expect(result).toBe(false);
    });

    test('应该在空权限时返回true', async () => {
      const result = await routerGuard.hasPermission([]);
      expect(result).toBe(true);
    });

    test('应该在无权限参数时返回true', async () => {
      const result = await routerGuard.hasPermission(null as any);
      expect(result).toBe(true);
    });
  });

  describe('hasRole方法', () => {
    beforeEach(() => {
      mockAuth.setAuthenticated(true);
      mockAuth.setUserInfo({
        permissions: ['read:user'],
        roles: ['admin', 'user']
      });
    });

    test('应该检查单个角色', async () => {
      const result = await routerGuard.hasRole('admin');
      expect(result).toBe(true);
    });

    test('应该检查多个角色（需要全部）', async () => {
      const result = await routerGuard.hasRole(['admin', 'user'], true);
      expect(result).toBe(true);
    });

    test('应该检查多个角色（需要任一）', async () => {
      const result = await routerGuard.hasRole(['admin', 'superuser'], false);
      expect(result).toBe(true);
    });

    test('应该在未认证时返回false', async () => {
      mockAuth.setAuthenticated(false);
      const result = await routerGuard.hasRole('admin');
      expect(result).toBe(false);
    });
  });

  describe('getCurrentUser方法', () => {
    test('应该返回当前用户信息', () => {
      const userInfo = { userId: '1', username: 'test' };
      mockAuth.setUserInfo(userInfo);
      
      const result = routerGuard.getCurrentUser();
      expect(result).toEqual(userInfo);
    });

    test('应该在获取用户信息失败时返回null', () => {
      // Mock getUserInfo 抛出异常
      jest.spyOn(mockAuth, 'getUserInfo').mockImplementation(() => {
        throw new Error('Failed to get user info');
      });
      
      const result = routerGuard.getCurrentUser();
      expect(result).toBeNull();
    });
  });

  describe('Vue路由守卫', () => {
    test('应该创建有效的路由守卫函数', () => {
      const guard = routerGuard.createVueGuard();
      expect(typeof guard).toBe('function');
    });

    test('应该正确处理允许的路由', async () => {
      mockAuth.setAuthenticated(true);
      mockAuth.setUserInfo({
        permissions: ['read:user'],
        roles: ['user']
      });

      const guard = routerGuard.createVueGuard();
      const to = { meta: { auth: { requiresAuth: true } } };
      const from = {};
      const next = jest.fn();

      await guard(to as any, from as any, next);
      expect(next).toHaveBeenCalledWith();
    });

    test('应该正确处理拒绝的路由', async () => {
      const guard = routerGuard.createVueGuard();
      const to = { meta: { auth: { requiresAuth: true } } };
      const from = {};
      const next = jest.fn();

      await guard(to as any, from as any, next);
      expect(next).toHaveBeenCalledWith(false);
    });

    test('应该处理路由守卫错误', async () => {
      // Mock check 方法抛出异常
      jest.spyOn(routerGuard, 'check').mockRejectedValue(new Error('Test error'));

      const guard = routerGuard.createVueGuard();
      const to = { meta: { auth: {} } };
      const from = {};
      const next = jest.fn();

      await guard(to as any, from as any, next);
      expect(next).toHaveBeenCalledWith(false);
    });
  });
});