/* eslint-disable @typescript-eslint/member-ordering, complexity */
import { CommonModule } from '@angular/common';
import {
  Component,
  DestroyRef,
  ElementRef,
  HostListener,
  computed,
  effect,
  inject,
  signal,
  viewChild
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { Store } from '@ngrx/store';
import { NgIcon, provideIcons } from '@ng-icons/core';
import {
  lucideHeadphones,
  lucideMaximize,
  lucideMic,
  lucideMicOff,
  lucideMinimize,
  lucideMonitor,
  lucideMonitorOff,
  lucidePhoneOff,
  lucideUsers,
  lucideVolume2,
  lucideVolumeX,
  lucideX
} from '@ng-icons/lucide';

import { User } from '../../../shared-kernel';
import {
  loadVoiceSettingsFromStorage,
  saveVoiceSettingsToStorage,
  VoiceSessionFacade,
  VoiceWorkspacePosition,
  VoiceWorkspaceService
} from '../../../domains/voice-session';
import { VoiceConnectionFacade, VoicePlaybackService } from '../../../domains/voice-connection';
import {
  ScreenShareFacade,
  ScreenShareQuality,
  ScreenShareStartOptions
} from '../../../domains/screen-share';
import { ViewportService } from '../../../core/platform';
import { selectCurrentRoom } from '../../../store/rooms/rooms.selectors';
import { UsersActions } from '../../../store/users/users.actions';
import { selectCurrentUser, selectOnlineUsers } from '../../../store/users/users.selectors';
import { ScreenShareQualityDialogComponent, UserAvatarComponent } from '../../../shared';
import { VoiceWorkspacePlaybackService } from './voice-workspace-playback.service';
import { VoiceWorkspaceStreamTileComponent } from './voice-workspace-stream-tile/voice-workspace-stream-tile.component';
import { VoiceWorkspaceStreamItem } from './voice-workspace.models';
import { ThemeNodeDirective } from '../../../domains/theme';
import { APP_TRANSLATE_IMPORTS, AppI18nService } from '../../../core/i18n';

@Component({
  selector: 'app-voice-workspace',
  standalone: true,
  imports: [
    CommonModule,
    NgIcon,
    ScreenShareQualityDialogComponent,
    VoiceWorkspaceStreamTileComponent,
    UserAvatarComponent,
    ThemeNodeDirective,
    ...APP_TRANSLATE_IMPORTS
  ],
  viewProviders: [
    provideIcons({
      lucideHeadphones,
      lucideMaximize,
      lucideMic,
      lucideMicOff,
      lucideMinimize,
      lucideMonitor,
      lucideMonitorOff,
      lucidePhoneOff,
      lucideUsers,
      lucideVolume2,
      lucideVolumeX,
      lucideX
    })
  ],
  templateUrl: './voice-workspace.component.html',
  host: {
    class: 'pointer-events-none absolute inset-0 z-20 block'
  }
})
export class VoiceWorkspaceComponent {
  private readonly destroyRef = inject(DestroyRef);
  private readonly elementRef = inject<ElementRef<HTMLElement>>(ElementRef);
  private readonly store = inject(Store);
  private readonly webrtc = inject(VoiceConnectionFacade);
  private readonly screenShare = inject(ScreenShareFacade);
  private readonly viewport = inject(ViewportService);
  readonly isMobile = this.viewport.isMobile;
  private readonly voicePlayback = inject(VoicePlaybackService);
  private readonly workspacePlayback = inject(VoiceWorkspacePlaybackService);
  private readonly voiceSession = inject(VoiceSessionFacade);
  private readonly voiceWorkspace = inject(VoiceWorkspaceService);
  private readonly appI18n = inject(AppI18nService);

  private readonly remoteStreamRevision = signal(0);

  private readonly miniWindowWidth = 320;
  private readonly miniWindowHeight = 228;
  private miniWindowDragging = false;
  private miniDragOffsetX = 0;
  private miniDragOffsetY = 0;
  private wasExpanded = false;
  private wasAutoHideChrome = false;
  private headerHideTimeoutId: ReturnType<typeof setTimeout> | null = null;
  private readonly observedRemoteStreams = new Map<string, {
    stream: MediaStream;
    cleanup: () => void;
  }>();

  readonly miniPreviewRef = viewChild<ElementRef<HTMLVideoElement>>('miniPreview');

  readonly currentRoom = this.store.selectSignal(selectCurrentRoom);
  readonly currentUser = this.store.selectSignal(selectCurrentUser);
  readonly onlineUsers = this.store.selectSignal(selectOnlineUsers);
  readonly voiceSessionInfo = this.voiceSession.voiceSession;

  readonly showExpanded = this.voiceWorkspace.isExpanded;
  readonly showMiniWindow = this.voiceWorkspace.isMinimized;
  readonly shouldConnectRemoteShares = this.voiceWorkspace.shouldConnectRemoteShares;
  readonly miniPosition = this.voiceWorkspace.miniWindowPosition;
  readonly showWorkspaceHeader = signal(true);

  readonly isConnected = computed(() => this.webrtc.isVoiceConnected());
  readonly isMuted = computed(() => this.webrtc.isMuted());
  readonly isDeafened = computed(() => this.webrtc.isDeafened());
  readonly isScreenSharing = computed(() => this.screenShare.isScreenSharing());

  readonly includeSystemAudio = signal(false);
  readonly screenShareQuality = signal<ScreenShareQuality>('balanced');
  readonly askScreenShareQuality = signal(true);
  readonly showScreenShareQualityDialog = signal(false);

  readonly connectedVoiceUsers = computed(() => {
    const room = this.currentRoom();
    const me = this.currentUser();
    const roomId = me?.voiceState?.roomId;
    const serverId = me?.voiceState?.serverId;

    if (!room || !roomId || !serverId || serverId !== room.id) {
      return [] as User[];
    }

    const voiceUsers = this.onlineUsers().filter(
      (user) =>
        !!user.voiceState?.isConnected
        && user.voiceState.roomId === roomId
        && user.voiceState.serverId === room.id
    );

    if (!me?.voiceState?.isConnected) {
      return voiceUsers;
    }

    const currentKeys = new Set(voiceUsers.map((user) => user.oderId || user.id));
    const meKey = me.oderId || me.id;

    if (meKey && !currentKeys.has(meKey)) {
      return [me, ...voiceUsers];
    }

    return voiceUsers;
  });

  readonly activeShares = computed<VoiceWorkspaceStreamItem[]>(() => {
    this.remoteStreamRevision();

    const room = this.currentRoom();
    const me = this.currentUser();
    const connectedRoomId = me?.voiceState?.roomId;
    const connectedServerId = me?.voiceState?.serverId;

    if (!room || !me || !connectedRoomId || connectedServerId !== room.id) {
      return [];
    }

    const shares: VoiceWorkspaceStreamItem[] = [];
    const localScreenStream = this.screenShare.screenStream();
    const localCameraStream = this.webrtc.isCameraEnabled()
      ? this.webrtc.getLocalCameraStream()
      : null;
    const localPeerKey = this.getUserPeerKey(me);

    if (localScreenStream && localPeerKey) {
      shares.push({
        id: this.buildStreamId(localPeerKey, 'screen'),
        peerKey: localPeerKey,
        user: me,
        stream: localScreenStream,
        isLocal: true,
        kind: 'screen',
        hasAudio: this.hasActiveAudio(localScreenStream)
      });
    }

    if (localCameraStream && localPeerKey) {
      shares.push({
        id: this.buildStreamId(localPeerKey, 'camera'),
        peerKey: localPeerKey,
        user: me,
        stream: localCameraStream,
        isLocal: true,
        kind: 'camera',
        hasAudio: false
      });
    }

    for (const user of this.onlineUsers()) {
      const peerKey = this.getUserPeerKey(user);

      if (!peerKey || peerKey === localPeerKey) {
        continue;
      }

      if (
        !user.voiceState?.isConnected
        || user.voiceState.roomId !== connectedRoomId
        || user.voiceState.serverId !== room.id
      ) {
        continue;
      }

      const remoteShare = user.screenShareState?.isSharing === false
        ? null
        : this.getRemoteScreenShareStream(user);

      if (remoteShare) {
        shares.push({
          id: this.buildStreamId(remoteShare.peerKey, 'screen'),
          peerKey: remoteShare.peerKey,
          user,
          stream: remoteShare.stream,
          isLocal: false,
          kind: 'screen',
          hasAudio: this.hasActiveAudio(remoteShare.stream)
        });
      }

      const remoteCamera = user.cameraState?.isEnabled === false
        ? null
        : this.getRemoteCameraStream(user);

      if (remoteCamera) {
        shares.push({
          id: this.buildStreamId(remoteCamera.peerKey, 'camera'),
          peerKey: remoteCamera.peerKey,
          user,
          stream: remoteCamera.stream,
          isLocal: false,
          kind: 'camera',
          hasAudio: false
        });
      }
    }

    return shares.sort((shareA, shareB) => {
      if (shareA.isLocal !== shareB.isLocal) {
        return shareA.isLocal ? 1 : -1;
      }

      if (shareA.kind !== shareB.kind) {
        return shareA.kind === 'screen' ? -1 : 1;
      }

      return shareA.user.displayName.localeCompare(shareB.user.displayName);
    });
  });

  readonly widescreenShareId = computed(() => {
    const requested = this.voiceWorkspace.focusedStreamId();
    const activeShares = this.activeShares();

    if (requested && activeShares.some((share) => share.id === requested)) {
      return requested;
    }

    if (activeShares.length === 1) {
      return activeShares[0].id;
    }

    return null;
  });

  readonly isWidescreenMode = computed(() => this.widescreenShareId() !== null);
  readonly shouldAutoHideChrome = computed(
    () => this.showExpanded() && this.isWidescreenMode() && this.activeShares().length > 0
  );
  readonly hasMultipleShares = computed(() => this.activeShares().length > 1);
  readonly widescreenShare = computed(
    () => this.activeShares().find((share) => share.id === this.widescreenShareId()) ?? null
  );
  readonly focusedAudioShare = computed(() => {
    const share = this.widescreenShare();

    return share && !share.isLocal && share.hasAudio ? share : null;
  });
  readonly focusedShareTitle = computed(() => {
    const share = this.widescreenShare();

    if (!share) {
      return this.appI18n.instant('voice.workspace.focusedStreamFallback');
    }

    if (!share.isLocal) {
      return share.user.displayName;
    }

    return share.kind === 'camera'
      ? this.appI18n.instant('voice.workspace.yourCamera')
      : this.appI18n.instant('voice.workspace.yourScreen');
  });
  readonly thumbnailShares = computed(() => {
    const widescreenShareId = this.widescreenShareId();

    if (!widescreenShareId) {
      return [] as VoiceWorkspaceStreamItem[];
    }

    return this.activeShares().filter((share) => share.id !== widescreenShareId);
  });
  readonly miniPreviewShare = computed(
    () => this.widescreenShare() ?? this.activeShares()[0] ?? null
  );
  readonly miniPreviewTitle = computed(() => {
    const previewShare = this.miniPreviewShare();

    if (!previewShare) {
      return this.appI18n.instant('voice.workspace.voiceWorkspace');
    }

    if (!previewShare.isLocal) {
      return previewShare.user.displayName;
    }

    return previewShare.kind === 'camera'
      ? this.appI18n.instant('voice.workspace.yourCamera')
      : this.appI18n.instant('voice.workspace.yourScreen');
  });
  readonly liveShareCount = computed(() => this.activeShares().length);
  readonly connectedVoiceChannelName = computed(() => {
    const me = this.currentUser();
    const room = this.currentRoom();
    const channelId = me?.voiceState?.roomId ?? this.voiceSessionInfo()?.roomId;
    const channel = room?.channels?.find(
      (candidate) => candidate.id === channelId && candidate.type === 'voice'
    );

    if (channel) {
      return channel.name;
    }

    const sessionRoomName = this.voiceSessionInfo()?.roomName?.replace(/^🔊\s*/, '');

    return sessionRoomName || this.appI18n.instant('voice.workspace.voiceLounge');
  });
  readonly serverName = computed(
    () => this.currentRoom()?.name || this.voiceSessionInfo()?.serverName || this.appI18n.instant('voice.workspace.voiceServer')
  );

  liveStreamCountLabel(count: number): string {
    const key = count === 1 ? 'voice.workspace.liveStream' : 'voice.workspace.liveStreams';

    return this.appI18n.instant(key, { count });
  }

  miniWindowStreamHint(count: number): string {
    const key = count === 1 ? 'voice.workspace.miniWindowHintSingle' : 'voice.workspace.miniWindowHint';

    return this.appI18n.instant(key, { count });
  }

  constructor() {
    this.destroyRef.onDestroy(() => {
      this.clearHeaderHideTimeout();
      this.cleanupObservedRemoteStreams();
      this.screenShare.syncRemoteScreenShareRequests([], false);
      this.workspacePlayback.teardownAll();
    });

    this.screenShare.onRemoteStream
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe(({ peerId }) => {
        this.observeRemoteStream(peerId);
        this.bumpRemoteStreamRevision();
      });

    this.screenShare.onPeerDisconnected
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe(() => this.bumpRemoteStreamRevision());

    effect(() => {
      const ref = this.miniPreviewRef();
      const previewShare = this.miniPreviewShare();
      const showMiniWindow = this.showMiniWindow();

      if (!ref) {
        return;
      }

      const video = ref.nativeElement;

      if (!showMiniWindow || !previewShare) {
        video.srcObject = null;
        return;
      }

      if (video.srcObject !== previewShare.stream) {
        video.srcObject = previewShare.stream;
      }

      video.muted = true;
      video.volume = 0;
      void video.play().catch(() => {});
    });

    effect(() => {
      if (!this.showMiniWindow()) {
        return;
      }

      requestAnimationFrame(() => this.ensureMiniWindowPosition());
    });

    effect(() => {
      const shouldConnectRemoteShares = this.shouldConnectRemoteShares();
      const currentUserPeerKey = this.getUserPeerKey(this.currentUser());
      const peerKeys = Array.from(new Set(
        this.connectedVoiceUsers()
          .map((user) => this.getUserPeerKey(user))
          .filter((peerKey): peerKey is string => !!peerKey && peerKey !== currentUserPeerKey)
      ));

      this.screenShare.syncRemoteScreenShareRequests(peerKeys, shouldConnectRemoteShares);

      if (!shouldConnectRemoteShares) {
        this.workspacePlayback.teardownAll();
      }
    });

    effect(() => {
      this.remoteStreamRevision();

      const room = this.currentRoom();
      const currentUser = this.currentUser();
      const connectedRoomId = currentUser?.voiceState?.roomId;
      const connectedServerId = currentUser?.voiceState?.serverId;
      const peerKeys = new Set<string>();

      if (room && connectedRoomId && connectedServerId === room.id) {
        for (const user of this.onlineUsers()) {
          if (
            !user.voiceState?.isConnected
            || user.voiceState.roomId !== connectedRoomId
            || user.voiceState.serverId !== room.id
          ) {
            continue;
          }

          for (const peerKey of [user.oderId, user.id]) {
            if (!peerKey || peerKey === this.getUserPeerKey(currentUser)) {
              continue;
            }

            peerKeys.add(peerKey);
            this.observeRemoteStream(peerKey);
          }
        }
      }

      this.pruneObservedRemoteStreams(peerKeys);
    });

    effect(() => {
      const isExpanded = this.showExpanded();
      const shouldAutoHideChrome = this.shouldAutoHideChrome();

      if (!isExpanded) {
        this.clearHeaderHideTimeout();
        this.showWorkspaceHeader.set(true);
        this.wasExpanded = false;
        this.wasAutoHideChrome = false;
        return;
      }

      if (!shouldAutoHideChrome) {
        this.clearHeaderHideTimeout();
        this.showWorkspaceHeader.set(true);
        this.wasExpanded = true;
        this.wasAutoHideChrome = false;
        return;
      }

      const shouldRevealChrome = !this.wasExpanded || !this.wasAutoHideChrome;

      this.wasExpanded = true;
      this.wasAutoHideChrome = true;

      if (shouldRevealChrome) {
        this.revealWorkspaceChrome();
      }
    });
  }

  onWorkspacePointerMove(): void {
    if (!this.shouldAutoHideChrome()) {
      return;
    }

    this.revealWorkspaceChrome();
  }

  @HostListener('window:mousemove', ['$event'])
  onWindowMouseMove(event: MouseEvent): void {
    if (!this.miniWindowDragging) {
      return;
    }

    event.preventDefault();

    const bounds = this.getWorkspaceBounds();
    const nextPosition = this.clampMiniWindowPosition({
      left: event.clientX - bounds.left - this.miniDragOffsetX,
      top: event.clientY - bounds.top - this.miniDragOffsetY
    });

    this.voiceWorkspace.setMiniWindowPosition(nextPosition);
  }

  @HostListener('window:mouseup')
  onWindowMouseUp(): void {
    this.miniWindowDragging = false;
  }

  @HostListener('window:resize')
  onWindowResize(): void {
    if (!this.showMiniWindow()) {
      return;
    }

    this.ensureMiniWindowPosition();
  }

  trackUser(index: number, user: User): string {
    return this.getUserPeerKey(user) || `${index}`;
  }

  trackShare(index: number, share: VoiceWorkspaceStreamItem): string {
    return share.id || `${index}`;
  }

  focusShare(peerKey: string): void {
    if (this.widescreenShareId() === peerKey) {
      return;
    }

    this.voiceWorkspace.focusStream(peerKey);
  }

  showAllStreams(): void {
    this.voiceWorkspace.clearFocusedStream();
  }

  minimizeWorkspace(): void {
    this.voiceWorkspace.minimize();
    this.ensureMiniWindowPosition();
  }

  restoreWorkspace(): void {
    this.voiceWorkspace.restore();
  }

  closeWorkspace(): void {
    this.voiceWorkspace.clearFocusedStream();
    this.voiceWorkspace.close();
  }

  focusedShareVolume(): number {
    const share = this.focusedAudioShare();

    if (!share) {
      return 100;
    }

    return this.workspacePlayback.getUserVolume(share.peerKey);
  }

  focusedShareMuted(): boolean {
    const share = this.focusedAudioShare();

    if (!share) {
      return false;
    }

    return this.workspacePlayback.isUserMuted(share.peerKey);
  }

  toggleFocusedShareMuted(): void {
    const share = this.focusedAudioShare();

    if (!share) {
      return;
    }

    this.workspacePlayback.setUserMuted(
      share.peerKey,
      !this.workspacePlayback.isUserMuted(share.peerKey)
    );
  }

  updateFocusedShareVolume(event: Event): void {
    const share = this.focusedAudioShare();

    if (!share) {
      return;
    }

    const input = event.target as HTMLInputElement;
    const nextVolume = Math.max(0, Math.min(100, parseInt(input.value, 10) || 0));

    this.workspacePlayback.setUserVolume(share.peerKey, nextVolume);

    if (nextVolume > 0 && this.workspacePlayback.isUserMuted(share.peerKey)) {
      this.workspacePlayback.setUserMuted(share.peerKey, false);
    }
  }

  startMiniWindowDrag(event: MouseEvent): void {
    const target = event.target as HTMLElement | null;

    if (target?.closest('button, input')) {
      return;
    }

    event.preventDefault();

    const bounds = this.getWorkspaceBounds();
    const currentPosition = this.voiceWorkspace.miniWindowPosition();

    this.miniWindowDragging = true;
    this.miniDragOffsetX = event.clientX - bounds.left - currentPosition.left;
    this.miniDragOffsetY = event.clientY - bounds.top - currentPosition.top;
  }

  toggleMute(): void {
    const nextMuted = !this.isMuted();

    this.webrtc.toggleMute(nextMuted);
    this.syncVoiceState({
      isConnected: this.isConnected(),
      isMuted: nextMuted,
      isDeafened: this.isDeafened()
    });

    this.broadcastVoiceState(nextMuted, this.isDeafened());
  }

  toggleDeafen(): void {
    const nextDeafened = !this.isDeafened();

    let nextMuted = this.isMuted();

    this.webrtc.toggleDeafen(nextDeafened);
    this.voicePlayback.updateDeafened(nextDeafened);

    if (nextDeafened && !nextMuted) {
      nextMuted = true;
      this.webrtc.toggleMute(true);
    }

    this.syncVoiceState({
      isConnected: this.isConnected(),
      isMuted: nextMuted,
      isDeafened: nextDeafened
    });

    this.broadcastVoiceState(nextMuted, nextDeafened);
  }

  async toggleScreenShare(): Promise<void> {
    if (this.isScreenSharing()) {
      this.screenShare.stopScreenShare();
      return;
    }

    this.syncScreenShareSettings();

    if (this.askScreenShareQuality()) {
      this.showScreenShareQualityDialog.set(true);
      return;
    }

    await this.startScreenShareWithOptions(this.screenShareQuality());
  }

  onScreenShareQualityCancelled(): void {
    this.showScreenShareQualityDialog.set(false);
  }

  async onScreenShareQualityConfirmed(quality: ScreenShareQuality): Promise<void> {
    this.showScreenShareQualityDialog.set(false);
    this.screenShareQuality.set(quality);
    saveVoiceSettingsToStorage({ screenShareQuality: quality });
    await this.startScreenShareWithOptions(quality);
  }

  disconnect(): void {
    this.webrtc.stopVoiceHeartbeat();

    this.webrtc.broadcastMessage({
      type: 'voice-state',
      oderId: this.currentUser()?.oderId || this.currentUser()?.id,
      displayName: this.currentUser()?.displayName || 'User',
      voiceState: {
        isConnected: false,
        isMuted: false,
        isDeafened: false,
        roomId: undefined,
        serverId: undefined
      }
    });

    if (this.isScreenSharing()) {
      this.screenShare.stopScreenShare();
    }

    this.webrtc.disableVoice();
    this.voicePlayback.teardownAll();
    this.voicePlayback.updateDeafened(false);

    const user = this.currentUser();

    if (user?.id) {
      this.store.dispatch(
        UsersActions.updateVoiceState({
          userId: user.id,
          voiceState: {
            isConnected: false,
            isMuted: false,
            isDeafened: false,
            roomId: undefined,
            serverId: undefined
          }
        })
      );

      this.store.dispatch(
        UsersActions.updateCameraState({
          userId: user.id,
          cameraState: { isEnabled: false }
        })
      );
    }

    this.voiceSession.endSession();
    this.voiceWorkspace.reset();
  }

  getControlButtonClass(
    isActive: boolean,
    accent: 'default' | 'primary' | 'danger' = 'default'
  ): string {
    const base = 'inline-flex min-w-[5.5rem] flex-col items-center gap-2 rounded-2xl px-4 py-3 text-sm font-medium transition-colors';

    if (accent === 'danger') {
      return `${base} bg-destructive text-destructive-foreground hover:bg-destructive/90`;
    }

    if (accent === 'primary' || isActive) {
      return `${base} bg-primary/15 text-primary hover:bg-primary/25`;
    }

    return `${base} bg-secondary/80 text-foreground hover:bg-secondary`;
  }

  private bumpRemoteStreamRevision(): void {
    this.remoteStreamRevision.update((value) => value + 1);
  }

  private syncVoiceState(voiceState: {
    isConnected: boolean;
    isMuted: boolean;
    isDeafened: boolean;
  }): void {
    const user = this.currentUser();
    const identifiers = this.getCurrentVoiceIdentifiers();

    if (!user?.id) {
      return;
    }

    this.store.dispatch(
      UsersActions.updateVoiceState({
        userId: user.id,
        voiceState: {
          ...voiceState,
          roomId: identifiers.roomId,
          serverId: identifiers.serverId
        }
      })
    );
  }

  private broadcastVoiceState(isMuted: boolean, isDeafened: boolean): void {
    const identifiers = this.getCurrentVoiceIdentifiers();

    this.webrtc.broadcastMessage({
      type: 'voice-state',
      oderId: this.currentUser()?.oderId || this.currentUser()?.id,
      displayName: this.currentUser()?.displayName || 'User',
      voiceState: {
        isConnected: this.isConnected(),
        isMuted,
        isDeafened,
        roomId: identifiers.roomId,
        serverId: identifiers.serverId
      }
    });
  }

  private getCurrentVoiceIdentifiers(): {
    roomId: string | undefined;
    serverId: string | undefined;
  } {
    const me = this.currentUser();

    return {
      roomId: me?.voiceState?.roomId ?? this.voiceSessionInfo()?.roomId,
      serverId: me?.voiceState?.serverId ?? this.currentRoom()?.id ?? this.voiceSessionInfo()?.serverId
    };
  }

  private syncScreenShareSettings(): void {
    const settings = loadVoiceSettingsFromStorage();

    this.includeSystemAudio.set(settings.includeSystemAudio);
    this.screenShareQuality.set(settings.screenShareQuality);
    this.askScreenShareQuality.set(settings.askScreenShareQuality);
  }

  private async startScreenShareWithOptions(quality: ScreenShareQuality): Promise<void> {
    const options: ScreenShareStartOptions = {
      includeSystemAudio: this.includeSystemAudio(),
      quality
    };

    try {
      await this.screenShare.startScreenShare(options);

      this.voiceWorkspace.open(null);
    } catch {
      // Screen-share prompt was dismissed or failed.
    }
  }

  private getUserPeerKey(user: User | null | undefined): string | null {
    return user?.oderId || user?.id || null;
  }

  private buildStreamId(peerKey: string, kind: VoiceWorkspaceStreamItem['kind']): string {
    return `${kind}:${peerKey}`;
  }

  private getRemoteScreenShareStream(user: User): { peerKey: string; stream: MediaStream } | null {
    const peerKeys = [user.oderId, user.id].filter(
      (candidate): candidate is string => !!candidate
    );

    for (const peerKey of peerKeys) {
      const stream = this.screenShare.getRemoteScreenShareStream(peerKey);

      if (stream && this.hasActiveVideo(stream)) {
        return { peerKey, stream };
      }
    }

    return null;
  }

  private getRemoteCameraStream(user: User): { peerKey: string; stream: MediaStream } | null {
    const peerKeys = [user.oderId, user.id].filter(
      (candidate): candidate is string => !!candidate
    );

    for (const peerKey of peerKeys) {
      const stream = this.webrtc.getRemoteCameraStream(peerKey);

      if (stream && this.hasActiveVideo(stream)) {
        return { peerKey, stream };
      }
    }

    return null;
  }

  private hasActiveVideo(stream: MediaStream): boolean {
    return stream.getVideoTracks().some((track) => track.readyState === 'live');
  }

  private hasActiveAudio(stream: MediaStream): boolean {
    return stream.getAudioTracks().some((track) => track.readyState === 'live');
  }

  private ensureMiniWindowPosition(): void {
    const bounds = this.getWorkspaceBounds();

    if (bounds.width === 0 || bounds.height === 0) {
      return;
    }

    if (!this.voiceWorkspace.hasCustomMiniWindowPosition()) {
      this.voiceWorkspace.setMiniWindowPosition(
        this.clampMiniWindowPosition({
          left: bounds.width - this.miniWindowWidth - 20,
          top: bounds.height - this.miniWindowHeight - 20
        }),
        false
      );

      return;
    }

    this.voiceWorkspace.setMiniWindowPosition(
      this.clampMiniWindowPosition(this.voiceWorkspace.miniWindowPosition()),
      true
    );
  }

  private clampMiniWindowPosition(position: VoiceWorkspacePosition): VoiceWorkspacePosition {
    const bounds = this.getWorkspaceBounds();
    const minLeft = 8;
    const minTop = 8;
    const maxLeft = Math.max(minLeft, bounds.width - this.miniWindowWidth - 8);
    const maxTop = Math.max(minTop, bounds.height - this.miniWindowHeight - 8);

    return {
      left: this.clamp(position.left, minLeft, maxLeft),
      top: this.clamp(position.top, minTop, maxTop)
    };
  }

  private getWorkspaceBounds(): DOMRect {
    return this.elementRef.nativeElement.getBoundingClientRect();
  }

  private observeRemoteStream(peerKey: string): void {
    const stream = this.screenShare.getRemoteScreenShareStream(peerKey);
    const existing = this.observedRemoteStreams.get(peerKey);

    if (!stream) {
      if (existing) {
        existing.cleanup();
        this.observedRemoteStreams.delete(peerKey);
      }

      return;
    }

    if (existing?.stream === stream) {
      return;
    }

    existing?.cleanup();

    const onChanged = () => this.bumpRemoteStreamRevision();
    const trackCleanups: (() => void)[] = [];
    const bindTrack = (track: MediaStreamTrack) => {
      if (track.kind !== 'video') {
        return;
      }

      const onTrackChanged = () => onChanged();

      track.addEventListener('ended', onTrackChanged);
      track.addEventListener('mute', onTrackChanged);
      track.addEventListener('unmute', onTrackChanged);

      trackCleanups.push(() => {
        track.removeEventListener('ended', onTrackChanged);
        track.removeEventListener('mute', onTrackChanged);
        track.removeEventListener('unmute', onTrackChanged);
      });
    };

    stream.getVideoTracks().forEach((track) => bindTrack(track));

    const onAddTrack = (event: MediaStreamTrackEvent) => {
      bindTrack(event.track);
      onChanged();
    };
    const onRemoveTrack = () => onChanged();

    stream.addEventListener('addtrack', onAddTrack);
    stream.addEventListener('removetrack', onRemoveTrack);

    this.observedRemoteStreams.set(peerKey, {
      stream,
      cleanup: () => {
        stream.removeEventListener('addtrack', onAddTrack);
        stream.removeEventListener('removetrack', onRemoveTrack);
        trackCleanups.forEach((cleanup) => cleanup());
      }
    });

    onChanged();
  }

  private pruneObservedRemoteStreams(activePeerKeys: Set<string>): void {
    for (const [peerKey, observed] of this.observedRemoteStreams.entries()) {
      if (activePeerKeys.has(peerKey)) {
        continue;
      }

      observed.cleanup();
      this.observedRemoteStreams.delete(peerKey);
    }
  }

  private cleanupObservedRemoteStreams(): void {
    for (const observed of this.observedRemoteStreams.values()) {
      observed.cleanup();
    }

    this.observedRemoteStreams.clear();
  }

  private scheduleHeaderHide(): void {
    this.clearHeaderHideTimeout();

    this.headerHideTimeoutId = setTimeout(() => {
      this.showWorkspaceHeader.set(false);
      this.headerHideTimeoutId = null;
    }, 2200);
  }

  private revealWorkspaceChrome(): void {
    this.showWorkspaceHeader.set(true);
    this.scheduleHeaderHide();
  }

  private clearHeaderHideTimeout(): void {
    if (this.headerHideTimeoutId === null) {
      return;
    }

    clearTimeout(this.headerHideTimeoutId);
    this.headerHideTimeoutId = null;
  }

  private clamp(value: number, min: number, max: number): number {
    return Math.min(Math.max(value, min), max);
  }
}
