import { Injectable } from '@nestjs/common';
import { Interval } from '@nestjs/schedule';
import { AppLoggerService } from 'src/common/services/logger.service';
import { ZOOM_ANALYTICS_DEFAULTS } from '../constants/zoom-analytics.constants';
import { ZoomAnalyticsConfigService } from '../services/zoom-analytics-config.service';
import { ZoomAnalyticsProviderRegistry } from '../registries/zoom-analytics-provider.registry';
import { ZoomAnalyticsSessionSummaryRepository } from '../repositories/zoom-analytics-session-summary.repository';
import { ZoomWebinarRepository } from '../repositories/zoom-webinar.repository';
import { ZoomDashboardApiClient } from '../services/zoom-dashboard-api.client';

/**
 * Optional self-heal poll for sessions currently marked live (`markStarted`
 * ran, `reconcile` hasn't). Cross-checks the webhook-built event log against
 * the Zoom Dashboard/Metrics API — the one Zoom endpoint with live data — and
 * corrects any drift (a missed leave/join webhook). Off by default
 * (ENABLE_ZOOM_ANALYTICS_LIVE_POLL) since Dashboard API access requires a
 * Business+ plan + `dashboard:read:list_meeting_participants:admin`/
 * `dashboard:read:list_webinar_participants:admin` scopes — confirmed
 * missing on this account's Server-to-Server app as of 2026-07-13; the
 * client itself already no-ops cleanly when that access is unavailable.
 */
@Injectable()
export class ZoomAnalyticsLivePollScheduler {
  constructor(
    private readonly config: ZoomAnalyticsConfigService,
    private readonly registry: ZoomAnalyticsProviderRegistry,
    private readonly webinarRepository: ZoomWebinarRepository,
    private readonly sessionSummaryRepository: ZoomAnalyticsSessionSummaryRepository,
    private readonly dashboardApiClient: ZoomDashboardApiClient,
    private readonly logger: AppLoggerService,
  ) {}

  @Interval(ZOOM_ANALYTICS_DEFAULTS.LIVE_POLL_INTERVAL_MS)
  async run(): Promise<void> {
    if (!this.config.isEnabled() || !this.config.isLivePollEnabled()) return;

    const liveSummaries = await this.sessionSummaryRepository.findLive();
    if (!liveSummaries.length) return;

    for (const summary of liveSummaries) {
      try {
        const session = await this.webinarRepository.findById(summary.sessionId);
        const extId = session?.onlineSession?.externalId;
        if (!session || !extId) continue;

        const participants = await this.dashboardApiClient.fetchLiveParticipants(
          extId,
          summary.resourceType,
        );
        if (participants === null) continue; // Dashboard API unavailable — no-op, not an error.

        // TEMP DEBUG — remove once we've confirmed which fields Zoom's live participants
        // response actually carries (device/os/browser) for this account/plan.
        this.logger.log('TEMP DEBUG: raw Zoom live participant fields', {
          sessionId: summary.sessionId,
          count: participants.length,
          sample: participants.slice(0, 3),
        });

        const currentlyPresent = new Map<string, string | null>();
        for (const p of participants) {
          const email = (p.user_email ?? p.email ?? '').trim().toLowerCase();
          if (!email) continue;
          currentlyPresent.set(email, p.user_name ?? p.name ?? null);
        }
        // Each summary row already carries its own resourceType (set by markStarted) — resolving
        // per-row lets webinar and meeting sessions both self-heal correctly in the same pass.
        const provider = this.registry.resolve(summary.resourceType);
        await provider.correctLiveState(session, currentlyPresent);
      } catch (error: any) {
        this.logger.error('Zoom analytics live-poll failed for session', error?.stack, {
          error,
          sessionId: summary.sessionId,
        });
      }
    }
  }
}
