import { ZoomAnalyticsProviderRegistry } from './zoom-analytics-provider.registry';
import { ZoomAnalyticsResourceType } from 'src/common/enum/zoom-analytics-resource-type.enum';
import { OnlineTypeEnum } from 'src/common/enum/online-type.enum';
import { InifniInternalServerErrorException } from 'src/common/exceptions/infini-internalservererror-exception';
import { AppLoggerService } from 'src/common/services/logger.service';

describe('ZoomAnalyticsProviderRegistry', () => {
  const logger = { warn: jest.fn(), log: jest.fn(), error: jest.fn() } as any;
  let registry: ZoomAnalyticsProviderRegistry;

  beforeAll(() => {
    // handleKnownErrors() reaches for AppLoggerService's static singleton directly.
    (AppLoggerService as any).instance = { error: jest.fn() };
  });

  beforeEach(() => {
    jest.clearAllMocks();
    registry = new ZoomAnalyticsProviderRegistry(logger);
  });

  it('registers and resolves a provider by resource type', () => {
    const provider = { key: ZoomAnalyticsResourceType.WEBINAR } as any;
    registry.register(ZoomAnalyticsResourceType.WEBINAR, provider);

    expect(registry.resolve(ZoomAnalyticsResourceType.WEBINAR)).toBe(provider);
    expect(registry.hasProvider(ZoomAnalyticsResourceType.WEBINAR)).toBe(true);
  });

  it('reports false for an unregistered resource type', () => {
    expect(registry.hasProvider(ZoomAnalyticsResourceType.MEETING)).toBe(false);
  });

  it('throws a mapped exception carrying the unsupported-resource-type code when resolving an unregistered resource type', () => {
    expect(() => registry.resolve(ZoomAnalyticsResourceType.MEETING)).toThrow(InifniInternalServerErrorException);
  });

  it('warns and overwrites when registering the same key twice', () => {
    const first = { key: ZoomAnalyticsResourceType.WEBINAR } as any;
    const second = { key: ZoomAnalyticsResourceType.WEBINAR } as any;

    registry.register(ZoomAnalyticsResourceType.WEBINAR, first);
    registry.register(ZoomAnalyticsResourceType.WEBINAR, second);

    expect(logger.warn).toHaveBeenCalled();
    expect(registry.resolve(ZoomAnalyticsResourceType.WEBINAR)).toBe(second);
  });

  describe('resolveForOnlineType', () => {
    it('maps OnlineTypeEnum.WEBINAR to the WEBINAR provider', () => {
      const webinarProvider = { key: ZoomAnalyticsResourceType.WEBINAR } as any;
      registry.register(ZoomAnalyticsResourceType.WEBINAR, webinarProvider);

      expect(registry.resolveForOnlineType(OnlineTypeEnum.WEBINAR)).toBe(webinarProvider);
    });

    it('maps OnlineTypeEnum.MEETING to the MEETING provider', () => {
      const meetingProvider = { key: ZoomAnalyticsResourceType.MEETING } as any;
      registry.register(ZoomAnalyticsResourceType.MEETING, meetingProvider);

      expect(registry.resolveForOnlineType(OnlineTypeEnum.MEETING)).toBe(meetingProvider);
    });

    it('throws a mapped exception for an online type with no analytics resource type (e.g. LIVE_STREAM)', () => {
      expect(() => registry.resolveForOnlineType(OnlineTypeEnum.LIVE_STREAM)).toThrow(
        InifniInternalServerErrorException,
      );
    });
  });
});
