import { UnauthorizedException } from '@nestjs/common';
import { RoleEnum } from '../../roles/roles.enum';
import { StatusEnum } from '../../statuses/statuses.enum';
import { JwtStrategy } from './jwt.strategy';

describe('JwtStrategy', () => {
  const jwtService = {} as any;
  const configService = { get: jest.fn(() => 'secret') } as any;
  let usersService: any;
  let strategy: JwtStrategy;

  beforeEach(() => {
    usersService = { findOne: jest.fn() };
    strategy = new JwtStrategy(jwtService, configService, usersService);
  });

  it('reloads the current database user and replaces a stale token role', async () => {
    usersService.findOne.mockResolvedValue({
      id: 2,
      role: { id: RoleEnum.user, name: 'User' },
      status: { id: StatusEnum.active, name: 'Active' },
      password: 'must-not-be-exposed',
    });

    const result = await strategy.validate({
      id: 2,
      role: { id: RoleEnum.admin },
      iat: 1,
      exp: 2,
    } as any);

    expect(usersService.findOne).toHaveBeenCalledWith({ id: 2 });
    expect(result).toEqual({
      id: 2,
      role: { id: RoleEnum.user, name: 'User' },
      status: { id: StatusEnum.active, name: 'Active' },
    });
    expect(result).not.toHaveProperty('password');
  });

  it('rejects a missing or soft-deleted database user', async () => {
    usersService.findOne.mockResolvedValue(undefined);

    await expect(
      strategy.validate({ id: 2, iat: 1, exp: 2 } as any),
    ).rejects.toBeInstanceOf(UnauthorizedException);
  });

  it('rejects an inactive current database user', async () => {
    usersService.findOne.mockResolvedValue({
      id: 2,
      role: { id: RoleEnum.user },
      status: { id: StatusEnum.inactive },
    });

    await expect(
      strategy.validate({ id: 2, iat: 1, exp: 2 } as any),
    ).rejects.toBeInstanceOf(UnauthorizedException);
  });

  it('rejects a payload without an id without querying the database', async () => {
    await expect(
      strategy.validate({ iat: 1, exp: 2 } as any),
    ).rejects.toBeInstanceOf(UnauthorizedException);
    expect(usersService.findOne).not.toHaveBeenCalled();
  });
});
