import { describe, it, expect, vi, beforeEach } from 'vitest';
import { AuthService, User, UserService } from '../../src/auth.service.js';
import { EnableStatus } from '@d8d/shared-types';

describe('认证服务', () => {
  let authService: AuthService;
  let mockUserService: UserService;

  const mockUser: User = {
    id: 1,
    username: 'testuser',
    nickname: '测试用户',
    isDisabled: EnableStatus.ENABLED,
    roles: [{ name: 'user' }]
  };

  beforeEach(() => {
    mockUserService = {
      getUserByUsername: vi.fn(),
      verifyPassword: vi.fn(),
      createUser: vi.fn()
    };

    authService = new AuthService(mockUserService);
    vi.stubEnv('JWT_SECRET', 'test-secret');
  });

  describe('登录', () => {
    it('应该成功登录', async () => {
      vi.mocked(mockUserService.getUserByUsername).mockResolvedValue(mockUser);
      vi.mocked(mockUserService.verifyPassword).mockResolvedValue(true);

      const result = await authService.login('testuser', 'password');

      expect(result.token).toBeDefined();
      expect(result.user).toEqual(mockUser);
      expect(mockUserService.getUserByUsername).toHaveBeenCalledWith('testuser');
      expect(mockUserService.verifyPassword).toHaveBeenCalledWith(mockUser, 'password');
    });

    it('用户不存在时应该抛出错误', async () => {
      vi.mocked(mockUserService.getUserByUsername).mockResolvedValue(null);

      await expect(authService.login('nonexistent', 'password'))
        .rejects
        .toThrow('用户不存在');
    });

    it('用户被禁用时应该抛出错误', async () => {
      const disabledUser = { ...mockUser, isDisabled: EnableStatus.DISABLED };
      vi.mocked(mockUserService.getUserByUsername).mockResolvedValue(disabledUser);

      await expect(authService.login('testuser', 'password'))
        .rejects
        .toThrow('用户账户已被禁用');
    });

    it('密码错误时应该抛出错误', async () => {
      vi.mocked(mockUserService.getUserByUsername).mockResolvedValue(mockUser);
      vi.mocked(mockUserService.verifyPassword).mockResolvedValue(false);

      await expect(authService.login('testuser', 'wrongpassword'))
        .rejects
        .toThrow('密码错误');
    });
  });

  describe('生成token', () => {
    it('应该成功生成token', () => {
      const token = authService.generateToken(mockUser);

      expect(token).toBeDefined();
      expect(typeof token).toBe('string');
    });

    it('应该使用自定义过期时间生成token', () => {
      const token = authService.generateToken(mockUser, '2h');

      expect(token).toBeDefined();
    });
  });

  describe('验证token', () => {
    it('应该成功验证token', () => {
      const token = authService.generateToken(mockUser);
      const payload = authService.verifyToken(token);

      expect(payload.id).toBe(mockUser.id);
      expect(payload.username).toBe(mockUser.username);
    });

    it('无效token应该抛出错误', () => {
      const invalidToken = 'invalid.token.here';

      expect(() => {
        authService.verifyToken(invalidToken);
      }).toThrow('无效的token');
    });
  });

  describe('权限验证', () => {
    it('应该验证用户有权限', () => {
      const hasPermission = authService.hasPermission(mockUser, 'user');

      expect(hasPermission).toBe(true);
    });

    it('应该验证用户没有权限', () => {
      const hasPermission = authService.hasPermission(mockUser, 'admin');

      expect(hasPermission).toBe(false);
    });

    it('应该验证用户有任意一个权限', () => {
      const hasAnyPermission = authService.hasAnyPermission(mockUser, ['user', 'admin']);

      expect(hasAnyPermission).toBe(true);
    });

    it('应该验证用户没有任意一个权限', () => {
      const hasAnyPermission = authService.hasAnyPermission(mockUser, ['admin', 'superuser']);

      expect(hasAnyPermission).toBe(false);
    });
  });

  describe('登出', () => {
    it('应该成功登出', async () => {
      const token = authService.generateToken(mockUser);

      await expect(authService.logout(token)).resolves.toBeUndefined();
    });

    it('无效token登出时应该抛出错误', async () => {
      const invalidToken = 'invalid.token.here';

      await expect(authService.logout(invalidToken))
        .rejects
        .toThrow('无效的token');
    });
  });
});