import { Test, TestingModule } from '@nestjs/testing';
import { ZoomAnalyticsWebhookController } from './zoom-analytics-webhook.controller';
import { ZoomAnalyticsWebhookService } from '../services/zoom-analytics-webhook.service';
import { ResponseService } from 'src/common/response-handling/response-handler';
import InifniBadRequestException from 'src/common/exceptions/infini-badrequest-exception';
import { ERROR_CODES } from 'src/common/constants/error-string-constants';

jest.mock('src/common/utils/controller-response-handling', () => ({
  handleControllerError: jest.fn((res, error) => res.json({ success: false, error })),
}));

const makeMockRes = () => ({
  json: jest.fn(),
  status: jest.fn().mockReturnThis(),
});

const makeMockReq = (body: unknown, headers: Record<string, unknown> = {}) => ({ body, headers });

describe('ZoomAnalyticsWebhookController', () => {
  let controller: ZoomAnalyticsWebhookController;

  const mockWebhookService = { process: jest.fn() };
  const mockResponseService = {
    success: jest.fn((res, _msg, data) => res.json({ success: true, data })),
  };

  beforeEach(async () => {
    jest.clearAllMocks();

    const module: TestingModule = await Test.createTestingModule({
      controllers: [ZoomAnalyticsWebhookController],
      providers: [
        { provide: ZoomAnalyticsWebhookService, useValue: mockWebhookService },
        { provide: ResponseService, useValue: mockResponseService },
      ],
    }).compile();

    controller = module.get<ZoomAnalyticsWebhookController>(ZoomAnalyticsWebhookController);
  });

  it('should be defined — no auth guards, this endpoint is public', () => {
    expect(controller).toBeDefined();
  });

  it('returns the raw { plainToken, encryptedToken } body Zoom requires — not the app envelope', async () => {
    const res = makeMockRes();
    const req = makeMockReq({ event: 'endpoint.url_validation', payload: { plainToken: 'abc' } });
    const validationResponse = { plainToken: 'abc', encryptedToken: 'hashed' };
    mockWebhookService.process.mockResolvedValue(validationResponse);

    await controller.receive(req as any, res as any);

    expect(mockWebhookService.process).toHaveBeenCalledWith(req.body, req.headers);
    expect(res.status).toHaveBeenCalledWith(200);
    expect(res.json).toHaveBeenCalledWith(validationResponse);
    expect(mockResponseService.success).not.toHaveBeenCalled();
  });

  it('acknowledges a normal event with no payload when the service returns void', async () => {
    const res = makeMockRes();
    const req = makeMockReq({ event: 'webinar.participant_joined' }, { 'x-zm-signature': 'v0=abc', 'x-zm-request-timestamp': '123' });
    mockWebhookService.process.mockResolvedValue(undefined);

    await controller.receive(req as any, res as any);

    expect(mockResponseService.success).toHaveBeenCalledWith(res, expect.any(String));
  });

  it('calls handleControllerError when signature verification fails', async () => {
    const res = makeMockRes();
    const req = makeMockReq({ event: 'webinar.participant_joined' }, { 'x-zm-signature': 'bad', 'x-zm-request-timestamp': '123' });
    mockWebhookService.process.mockRejectedValue(
      new InifniBadRequestException(ERROR_CODES.ZOOM_WEBHOOK_INVALID_SIGNATURE),
    );

    await controller.receive(req as any, res as any);

    expect(res.json).toHaveBeenCalledWith(expect.objectContaining({ success: false }));
  });
});
