/* eslint-disable max-statements-per-line */
/**
 * Lightweight logging utility for the WebRTC subsystem.
 * All log lines are prefixed with `[WebRTC]`.
 */
export interface WebRTCTrafficDetails {
  [key: string]: unknown;
  bytes?: number;
  bufferedAmount?: number;
  channelLabel?: string;
  messageId?: string;
  payloadPreview?: unknown;
  peerId?: string;
  readyState?: number | string | null;
  roomId?: string;
  targetPeerId?: string;
  type?: string;
  url?: string | null;
}

export class WebRTCLogger {
  constructor(private readonly isEnabled: boolean | (() => boolean) = true) {}

  /** Informational log (only when debug is enabled). */
  info(prefix: string, ...args: unknown[]): void {
    if (!this.isDebugEnabled())
      return;

    try { console.log(`[WebRTC] ${prefix}`, ...args); } catch { /* swallow */ }
  }

  /** Warning log (only when debug is enabled). */
  warn(prefix: string, ...args: unknown[]): void {
    if (!this.isDebugEnabled())
      return;

    try { console.warn(`[WebRTC] ${prefix}`, ...args); } catch { /* swallow */ }
  }

  /** Structured network-traffic log for signaling and data-channel activity. */
  traffic(scope: 'data-channel' | 'signaling', direction: 'inbound' | 'outbound', details: WebRTCTrafficDetails): void {
    this.info(`[${scope}] ${direction}`, details);
  }

  /** Error log (always emitted regardless of debug flag). */
  error(prefix: string, err: unknown, extra?: Record<string, unknown>): void {
    const errorDetails = this.extractErrorDetails(err);
    const payload = {
      name: errorDetails.name,
      message: errorDetails.message,
      stack: errorDetails.stack,
      ...extra
    };

    try { console.error(`[WebRTC] ${prefix}`, payload); } catch { /* swallow */ }
  }

  /** Attach lifecycle event listeners to a track for debugging. */
  attachTrackDiagnostics(track: MediaStreamTrack, label: string): void {
    const settings = typeof track.getSettings === 'function' ? track.getSettings() : {} as MediaTrackSettings;

    this.info(`Track attached: ${label}`, {
      id: track.id,
      kind: track.kind,
      readyState: track.readyState,
      contentHint: track.contentHint,
      settings
    });

    track.addEventListener('ended', () => this.warn(`Track ended: ${label}`, { id: track.id,
      kind: track.kind }));

    track.addEventListener('mute', () => this.warn(`Track muted: ${label}`, { id: track.id,
      kind: track.kind }));

    track.addEventListener('unmute', () => this.info(`Track unmuted: ${label}`, { id: track.id,
      kind: track.kind }));
  }

  /** Log a MediaStream summary and attach diagnostics to every track. */
  logStream(label: string, stream: MediaStream | null): void {
    if (!stream) {
      this.warn(`Stream missing: ${label}`);
      return;
    }

    const audioTracks = stream.getAudioTracks();
    const videoTracks = stream.getVideoTracks();

    this.info(`Stream ready: ${label}`, {
      id: stream.id,
      audioTrackCount: audioTracks.length,
      videoTrackCount: videoTracks.length,
      allTrackIds: stream.getTracks().map(streamTrack => ({ id: streamTrack.id,
        kind: streamTrack.kind }))
    });

    audioTracks.forEach((audioTrack, index) => this.attachTrackDiagnostics(audioTrack, `${label}:audio#${index}`));
    videoTracks.forEach((videoTrack, index) => this.attachTrackDiagnostics(videoTrack, `${label}:video#${index}`));
  }

  private isDebugEnabled(): boolean {
    return typeof this.isEnabled === 'function'
      ? this.isEnabled()
      : this.isEnabled;
  }

  private extractErrorDetails(err: unknown): {
    name?: unknown;
    message?: unknown;
    stack?: unknown;
  } {
    if (typeof err !== 'object' || err === null) {
      return {};
    }

    const candidate = err as {
      name?: unknown;
      message?: unknown;
      stack?: unknown;
    };

    return {
      name: candidate.name,
      message: candidate.message,
      stack: candidate.stack
    };
  }
}
