import * as bcrypt from 'bcryptjs';
import { AuthService } from './auth.service';

describe('AuthService — authentication boundaries', () => {
  it('marks the preset 超管 role as super admin in the JWT payload', async () => {
    const userRepo = {
      findOne: jest.fn().mockResolvedValue({
        id: 1,
        username: 'admin',
        name: '管理员',
        passwordHash: await bcrypt.hash('secret', 4),
        isActive: true,
        roles: [{ name: '超管', status: 1 }],
      }),
      save: jest.fn(),
    };
    const jwtService = { sign: jest.fn().mockReturnValue('token') };
    const rbacService = {
      getUserPermissions: jest.fn().mockResolvedValue(['attendance:create']),
    };
    const service = new AuthService(userRepo as never, jwtService as never, rbacService as never);

    await service.login({ username: 'admin', password: 'secret' }, '127.0.0.1');

    expect(jwtService.sign).toHaveBeenCalledWith(expect.objectContaining({ isSuperAdmin: true }));
  });
  it('rejects an archived user even when the password is valid', async () => {
    const userRepo = {
      findOne: jest.fn().mockResolvedValue({
        id: 2,
        username: 'archived',
        passwordHash: await bcrypt.hash('secret', 4),
        isActive: true,
        isArchived: true,
        roles: [],
      }),
      save: jest.fn(),
    };
    const service = new AuthService(
      userRepo as never,
      { sign: jest.fn() } as never,
      { getUserPermissions: jest.fn() } as never,
    );

    await expect(
      service.login({ username: 'archived', password: 'secret' }, '192.0.2.10'),
    ).rejects.toThrow('账号已失效');
    expect(userRepo.save).not.toHaveBeenCalled();
  });
});
