import { Injectable } from '@nestjs/common';
import { AppLoggerService } from 'src/common/services/logger.service';
import { handleKnownErrors } from 'src/common/utils/handle-error.util';
import { ERROR_CODES } from 'src/common/constants/error-string-constants';
import { OnlineTypeEnum } from 'src/common/enum/online-type.enum';
import { ZoomAnalyticsResourceType } from 'src/common/enum/zoom-analytics-resource-type.enum';
import { ZoomAnalyticsProvider } from '../interfaces/zoom-analytics-provider.interface';

const ONLINE_TYPE_TO_RESOURCE_TYPE: Partial<Record<OnlineTypeEnum, ZoomAnalyticsResourceType>> = {
  [OnlineTypeEnum.WEBINAR]: ZoomAnalyticsResourceType.WEBINAR,
  [OnlineTypeEnum.MEETING]: ZoomAnalyticsResourceType.MEETING,
};

/**
 * Maps a Zoom analytics resource type to its provider implementation.
 * Providers self-register in their own `onModuleInit` — exactly the same
 * idiom as `OnlineSessionProviderRegistry` — so adding a new resource type
 * (or replacing Webinar/Meeting) touches zero existing files, just a new
 * provider class.
 */
@Injectable()
export class ZoomAnalyticsProviderRegistry {
  private readonly providers = new Map<ZoomAnalyticsResourceType, ZoomAnalyticsProvider>();

  constructor(private readonly logger: AppLoggerService) {}

  register(key: ZoomAnalyticsResourceType, provider: ZoomAnalyticsProvider): void {
    if (this.providers.has(key)) {
      this.logger.warn(`Zoom analytics provider overwritten for resource type: ${key}`);
    }
    this.providers.set(key, provider);
    this.logger.log(`Zoom analytics provider registered for resource type: ${key}`);
  }

  /** Resolve a provider or throw a mapped bad-request when unsupported. */
  resolve(key: ZoomAnalyticsResourceType): ZoomAnalyticsProvider {
    const provider = this.providers.get(key);
    if (!provider) {
      handleKnownErrors(
        ERROR_CODES.ZOOM_ANALYTICS_RESOURCE_TYPE_NOT_SUPPORTED,
        new Error(`No Zoom analytics provider registered for resource type: ${key}`),
      );
    }
    return provider;
  }

  /**
   * Resolves the provider for a session's own `onlineType` — the correct way
   * to pick a provider for a specific session/webhook. Every session carries
   * its resource type on the row itself, so there is never a need to fall
   * back to a global default.
   */
  resolveForOnlineType(onlineType: OnlineTypeEnum): ZoomAnalyticsProvider {
    const resourceType = ONLINE_TYPE_TO_RESOURCE_TYPE[onlineType];
    if (!resourceType) {
      handleKnownErrors(
        ERROR_CODES.ZOOM_ANALYTICS_RESOURCE_TYPE_NOT_SUPPORTED,
        new Error(`Zoom analytics unsupported for online type: ${onlineType}`),
      );
    }
    return this.resolve(resourceType);
  }

  hasProvider(key: ZoomAnalyticsResourceType): boolean {
    return this.providers.has(key);
  }
}
