import { Test, TestingModule } from '@nestjs/testing';
import { InvalidClientError, InvalidRequestError } from '../../domain/errors';
import type { OAuthRevokeTokenInput } from '../../domain/flows.types';
import { OAuthRevokeTokenHandler } from './o-auth-revoke-token.handler';
import { OAuthRevokeTokenService } from './services/o-auth-revoke-token.service';

const buildInput = (overrides: Partial<OAuthRevokeTokenInput> = {}): OAuthRevokeTokenInput => ({
  clientId: 'aurora',
  clientSecret: 'top-secret-12345',
  token: 'opaque-refresh-token-value',
  ...overrides,
});

describe('OAuthRevokeTokenHandler', () => {
  let handler: OAuthRevokeTokenHandler;
  let service: { main: jest.Mock };

  beforeEach(async () => {
    service = { main: jest.fn().mockResolvedValue({ revoked: true }) };

    const module: TestingModule = await Test.createTestingModule({
      providers: [OAuthRevokeTokenHandler, { provide: OAuthRevokeTokenService, useValue: service }],
    }).compile();

    handler = module.get(OAuthRevokeTokenHandler);
  });

  describe('invalid_client', () => {
    it('throws InvalidClientError when clientId is empty, without calling the service', async () => {
      await expect(handler.main(buildInput({ clientId: '' }))).rejects.toBeInstanceOf(
        InvalidClientError,
      );
      expect(service.main).not.toHaveBeenCalled();
    });

    it('throws InvalidClientError when clientSecret is empty, without calling the service', async () => {
      await expect(handler.main(buildInput({ clientSecret: '' }))).rejects.toBeInstanceOf(
        InvalidClientError,
      );
      expect(service.main).not.toHaveBeenCalled();
    });
  });

  describe('invalid_request', () => {
    it('throws InvalidRequestError when token is empty, without calling the service', async () => {
      await expect(handler.main(buildInput({ token: '' }))).rejects.toBeInstanceOf(
        InvalidRequestError,
      );
      expect(service.main).not.toHaveBeenCalled();
    });
  });

  describe('delegation', () => {
    it('delegates to the service and returns its response on valid input', async () => {
      const input = buildInput();

      const result = await handler.main(input);

      expect(service.main).toHaveBeenCalledWith(input);
      expect(result).toEqual({ revoked: true });
    });
  });
});
