import { ZoomReportApiClient } from './zoom-report-api.client';

describe('ZoomReportApiClient', () => {
  const http = { get: jest.fn() };
  const logger = { warn: jest.fn() };

  let client: ZoomReportApiClient;

  beforeEach(() => {
    jest.clearAllMocks();
    client = new ZoomReportApiClient(http as any, logger as any);
  });

  it('returns the report payload on success', async () => {
    const report = { start_time: '2026-07-13T10:00:00Z', duration: 60 };
    http.get.mockResolvedValue(report);

    const result = await client.fetchMeetingReport('123');

    expect(http.get).toHaveBeenCalledWith('/report/meetings/123');
    expect(result).toBe(report);
  });

  it('hits the webinar report path for webinars', async () => {
    http.get.mockResolvedValue({});

    await client.fetchWebinarReport('456');

    expect(http.get).toHaveBeenCalledWith('/report/webinars/456');
  });

  it.each([
    ['404 not found', { response: { status: 404 } }],
    ['code 3001 (report not generated yet)', { response: { status: 400, data: { code: 3001 } } }],
  ])('returns null on %s', async (_label, error) => {
    http.get.mockRejectedValue(error);

    await expect(client.fetchMeetingReport('123')).resolves.toBeNull();
    expect(logger.warn).not.toHaveBeenCalled();
  });

  it('degrades to null (warns once) on the granular-scope 400/4711 rejection instead of failing reconcile', async () => {
    http.get.mockRejectedValue({
      response: {
        status: 400,
        data: { code: 4711, message: 'Invalid access token, does not contain scopes:[report:read:meeting:admin].' },
      },
    });

    await expect(client.fetchMeetingReport('123')).resolves.toBeNull();
    await expect(client.fetchMeetingReport('123')).resolves.toBeNull();
    expect(logger.warn).toHaveBeenCalledTimes(1);
  });

  it('degrades to null on any other 400 rejection (Zoom 400 codes vary) instead of failing reconcile', async () => {
    http.get.mockRejectedValue({ response: { status: 400, data: { code: 200, message: 'plan gate' } } });

    await expect(client.fetchMeetingReport('123')).resolves.toBeNull();
    expect(logger.warn).toHaveBeenCalledTimes(1);
  });

  it.each([401, 403])('degrades to null on a %d response', async (status) => {
    http.get.mockRejectedValue({ response: { status } });

    await expect(client.fetchWebinarReport('456')).resolves.toBeNull();
  });

  it('rethrows on an unexpected error status', async () => {
    http.get.mockRejectedValue({ response: { status: 500 } });

    await expect(client.fetchMeetingReport('123')).rejects.toBeDefined();
  });
});
