import { UnauthorizedException } from '@nestjs/common';
import { JwtStrategy } from './jwt.strategy';

describe('JwtStrategy', () => {
  const config = { get: jest.fn().mockReturnValue('secret') };

  it('refreshes permissions from the database instead of trusting stale JWT permissions', async () => {
    const userRepo = {
      findOne: jest.fn().mockResolvedValue({
        id: 7,
        username: 'teacher',
        isActive: true,
        isArchived: false,
        roles: [
          {
            name: '老师',
            status: 1,
            permissions: [{ code: 'class:view' }, { code: 'attendance:view' }],
          },
        ],
      }),
    };
    const strategy = new JwtStrategy(config as never, userRepo as never);

    await expect(
      strategy.validate({ sub: 7, username: 'teacher', permissions: ['user:delete'] }),
    ).resolves.toEqual({
      id: 7,
      username: 'teacher',
      permissions: ['class:view', 'attendance:view'],
      isSuperAdmin: false,
      roles: ['老师'],
    });
  });

  it('recognizes the canonical super_admin role code even when the display name changes', async () => {
    const userRepo = {
      findOne: jest.fn().mockResolvedValue({
        id: 1,
        username: 'admin',
        isActive: true,
        isArchived: false,
        roles: [{ name: '系统管理员', code: 'super_admin', status: 1, permissions: [] }],
      }),
    };
    const strategy = new JwtStrategy(config as never, userRepo as never);

    await expect(strategy.validate({ sub: 1 })).resolves.toEqual(
      expect.objectContaining({ isSuperAdmin: true }),
    );
  });

  it.each([
    [{ id: 7, isActive: false, isArchived: false, roles: [] }],
    [{ id: 7, isActive: true, isArchived: true, roles: [] }],
    [null],
  ])('rejects disabled, archived, or deleted users', async (user) => {
    const userRepo = { findOne: jest.fn().mockResolvedValue(user) };
    const strategy = new JwtStrategy(config as never, userRepo as never);

    await expect(strategy.validate({ sub: 7, username: 'teacher' })).rejects.toBeInstanceOf(
      UnauthorizedException,
    );
  });
});
