/**
 * AdminGuard 单元测试
 * 
 * 功能描述：
 * - 测试管理员鉴权守卫的权限验证逻辑
 * - 验证Token解析和验证的正确性
 * - 测试各种异常情况的处理
 * 
 * 职责分离：
 * - 权限验证测试，专注守卫逻辑
 * - Mock核心服务，测试守卫行为
 * - 验证请求拦截和放行的正确性
 * 
 * 最近修改：
 * - 2026-01-08: 注释规范优化 - 添加文件头注释，完善测试文档说明 (修改者: moyin)
 * 
 * @author moyin
 * @version 1.0.1
 * @since 2025-12-19
 * @lastModified 2026-01-08
 */

import { ExecutionContext, UnauthorizedException } from '@nestjs/common';
import { AdminCoreService, AdminAuthPayload } from '../../core/admin_core/admin_core.service';
import { AdminGuard } from './admin.guard';

describe('AdminGuard', () => {
  const payload: AdminAuthPayload = {
    adminId: '1',
    username: 'admin',
    role: 9,
    iat: 1,
    exp: 2,
  };

  const adminCoreServiceMock: Pick<AdminCoreService, 'verifyToken'> = {
    verifyToken: jest.fn(),
  };

  const makeContext = (authorization?: any) => {
    const req: any = { headers: {} };
    if (authorization !== undefined) {
      req.headers['authorization'] = authorization;
    }

    const ctx: Partial<ExecutionContext> = {
      switchToHttp: () => ({
        getRequest: () => req,
        getResponse: () => ({} as any),
        getNext: () => ({} as any),
      }),
    };

    return { ctx: ctx as ExecutionContext, req };
  };

  beforeEach(() => {
    jest.resetAllMocks();
  });

  it('should allow access with valid admin token', () => {
    (adminCoreServiceMock.verifyToken as jest.Mock).mockReturnValue(payload);

    const guard = new AdminGuard(adminCoreServiceMock as AdminCoreService);
    const { ctx, req } = makeContext('Bearer valid');

    expect(guard.canActivate(ctx)).toBe(true);
    expect(adminCoreServiceMock.verifyToken).toHaveBeenCalledWith('valid');
    expect(req.admin).toEqual(payload);
  });

  it('should deny access without token', () => {
    const guard = new AdminGuard(adminCoreServiceMock as AdminCoreService);
    const { ctx } = makeContext(undefined);

    expect(() => guard.canActivate(ctx)).toThrow(UnauthorizedException);
  });

  it('should deny access with invalid Authorization format', () => {
    const guard = new AdminGuard(adminCoreServiceMock as AdminCoreService);
    const { ctx } = makeContext('InvalidFormat');

    expect(() => guard.canActivate(ctx)).toThrow(UnauthorizedException);
  });

  it('should deny access when verifyToken throws (invalid/expired)', () => {
    (adminCoreServiceMock.verifyToken as jest.Mock).mockImplementation(() => {
      throw new UnauthorizedException('Token已过期');
    });

    const guard = new AdminGuard(adminCoreServiceMock as AdminCoreService);
    const { ctx } = makeContext('Bearer bad');

    expect(() => guard.canActivate(ctx)).toThrow(UnauthorizedException);
  });

  it('should deny access when Authorization header is an array', () => {
    const guard = new AdminGuard(adminCoreServiceMock as AdminCoreService);
    const { ctx } = makeContext(['Bearer token']);

    expect(() => guard.canActivate(ctx)).toThrow(UnauthorizedException);
  });
});
