import { MediaManager } from './media.manager';
import { LatencyProfile } from '../realtime.constants';
import { VoiceStateSnapshot } from '../realtime.types';

interface VoiceSessionControllerDependencies {
  mediaManager: MediaManager;
  getIsScreenSharing(): boolean;
  setVoiceConnected(connected: boolean): void;
  setMuted(muted: boolean): void;
  setDeafened(deafened: boolean): void;
  setNoiseReductionEnabled(enabled: boolean): void;
}

export class VoiceSessionController {
  private voiceServerId: string | null = null;

  constructor(
    private readonly dependencies: VoiceSessionControllerDependencies
  ) {}

  getVoiceServerId(): string | null {
    return this.voiceServerId;
  }

  getEffectiveServerId(activeServerId: string | null): string | null {
    return this.voiceServerId || activeServerId;
  }

  handleVoiceConnected(): void {
    this.dependencies.setVoiceConnected(true);
  }

  getCurrentVoiceState(): VoiceStateSnapshot {
    return {
      isConnected: this.dependencies.mediaManager.getIsVoiceActive(),
      isMuted: this.dependencies.mediaManager.getIsMicMuted(),
      isDeafened: this.dependencies.mediaManager.getIsSelfDeafened(),
      isScreenSharing: this.dependencies.getIsScreenSharing(),
      roomId: this.dependencies.mediaManager.getCurrentVoiceRoomId(),
      serverId: this.dependencies.mediaManager.getCurrentVoiceServerId()
    };
  }

  async enableVoice(): Promise<MediaStream> {
    const stream = await this.dependencies.mediaManager.enableVoice();

    this.syncMediaSignals();
    return stream;
  }

  disableVoice(): void {
    this.voiceServerId = null;
    this.dependencies.mediaManager.disableVoice();
    this.dependencies.setVoiceConnected(false);
  }

  async setLocalStream(stream: MediaStream): Promise<void> {
    await this.dependencies.mediaManager.setLocalStream(stream);
    this.syncMediaSignals();
  }

  toggleMute(muted?: boolean): void {
    this.dependencies.mediaManager.toggleMute(muted);
    this.dependencies.setMuted(this.dependencies.mediaManager.getIsMicMuted());
  }

  toggleDeafen(deafened?: boolean): void {
    this.dependencies.mediaManager.toggleDeafen(deafened);
    this.dependencies.setDeafened(this.dependencies.mediaManager.getIsSelfDeafened());
  }

  async toggleNoiseReduction(enabled?: boolean): Promise<void> {
    await this.dependencies.mediaManager.toggleNoiseReduction(enabled);
    this.dependencies.setNoiseReductionEnabled(this.dependencies.mediaManager.getIsNoiseReductionEnabled());
  }

  setOutputVolume(volume: number): void {
    this.dependencies.mediaManager.setOutputVolume(volume);
  }

  setInputVolume(volume: number): void {
    this.dependencies.mediaManager.setInputVolume(volume);
  }

  async setAudioBitrate(kbps: number): Promise<void> {
    return await this.dependencies.mediaManager.setAudioBitrate(kbps);
  }

  async setLatencyProfile(profile: LatencyProfile): Promise<void> {
    return await this.dependencies.mediaManager.setLatencyProfile(profile);
  }

  startVoiceHeartbeat(roomId?: string, serverId?: string): void {
    if (serverId) {
      this.voiceServerId = serverId;
    }

    this.dependencies.mediaManager.startVoiceHeartbeat(roomId, serverId);
  }

  stopVoiceHeartbeat(): void {
    this.dependencies.mediaManager.stopVoiceHeartbeat();
  }

  resetVoiceSession(): void {
    this.voiceServerId = null;
    this.dependencies.mediaManager.stopVoiceHeartbeat();
    this.dependencies.mediaManager.disableVoice();
    this.dependencies.setVoiceConnected(false);
  }

  private syncMediaSignals(): void {
    this.dependencies.setVoiceConnected(this.dependencies.mediaManager.getIsVoiceActive());
    this.dependencies.setMuted(this.dependencies.mediaManager.getIsMicMuted());
    this.dependencies.setDeafened(this.dependencies.mediaManager.getIsSelfDeafened());
  }
}
