import { ProgramSession, ProgramRegistrationOnlineSession } from 'src/common/entities';
import {
  CreateSessionInput,
  UpdateSessionInput,
  CreateSharedSessionInput,
} from 'src/common/interfaces/online-session.interface';
import { ZoomRole } from '../enums/zoom-role.enum';

/** Registrant contact, derived from the program registration. */
export interface ZoomContactInfo {
  firstName: string;
  lastName?: string;
  email: string;
  name: string;
}

/** Outcome of adding a participant to the Zoom resource. */
export interface ZoomParticipantResult {
  joinUrl: string | null;
  zoomRegistrantId: string | null;
  isPanelist: boolean;
}

/**
 * One session type (webinar or meeting). Each implementation owns the bits that
 * actually differ between types — session lifecycle AND participant add/remove;
 * everything shared lives in ZoomSessionBase / ZoomRegistrationService.
 */
export interface ZoomSessionHandler {
  create(input: CreateSessionInput): Promise<ProgramSession>;
  update(session: ProgramSession, input: UpdateSessionInput): Promise<ProgramSession>;
  remove(session: ProgramSession, actorUserId?: number): Promise<void>;

  /**
   * Provisions ONE recurring resource ("same link") shared across several program
   * sessions, one online-session row per session. Implemented once in
   * ZoomSessionBase via per-type hooks.
   */
  createSharedGroup(input: CreateSharedSessionInput): Promise<ProgramSession[]>;

  /**
   * Adds a participant to the live Zoom resource (registrant/panelist/shared-link).
   * When `ZOOM_MANUAL_APPROVAL_REGISTRANTS` is on, the resource requires manual
   * registrant approval, so a registrant (non-panelist) is created `pending`
   * unless `autoApprove` is set — every caller in this codebase (real
   * ProgramRegistration signups AND generated/staff links) passes `true`, since
   * both originate from our own backend and neither needs the pending state.
   * Leave it `false` (default) only for a registrant whose approval genuinely
   * should wait on manual review. No-op (registrant is already approved) when
   * that flag is off.
   */
  addParticipant(
    session: ProgramSession,
    contact: ZoomContactInfo,
    role: ZoomRole,
    autoApprove?: boolean,
  ): Promise<ZoomParticipantResult>;

  /**
   * Revokes a participant's join access on the live Zoom resource. For a
   * registrant this cancels their Zoom registration (status endpoint) rather
   * than deleting it, so {@link approveParticipant} can restore the same join
   * link later; a panelist has no status concept in Zoom's API and is removed
   * outright. `contact` supplies the email Zoom's status endpoint expects
   * alongside the registrant id — null when unavailable.
   */
  removeParticipant(
    session: ProgramSession,
    extension: ProgramRegistrationOnlineSession,
    contact: ZoomContactInfo | null,
  ): Promise<void>;

  /**
   * Restores a previously cancelled registrant (see {@link removeParticipant})
   * to active status, reusing their existing Zoom registrant id and join link
   * instead of registering them again. Falls back to {@link addParticipant}
   * when the extension holds no prior registrant id (never registered, or a
   * shared-link meeting with no per-user registrant).
   */
  approveParticipant(
    session: ProgramSession,
    extension: ProgramRegistrationOnlineSession,
    contact: ZoomContactInfo,
  ): Promise<ZoomParticipantResult>;
}
