/* eslint-disable @typescript-eslint/member-ordering, @typescript-eslint/no-unused-vars */
import {
  Component,
  inject,
  signal,
  computed,
  OnInit
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { Store } from '@ngrx/store';
import { NgIcon, provideIcons } from '@ng-icons/core';
import {
  lucideMic,
  lucideMicOff,
  lucideMonitor,
  lucideMonitorOff,
  lucidePhoneOff,
  lucideHeadphones,
  lucideArrowLeft
} from '@ng-icons/lucide';

import { VoiceSessionFacade } from '../../application/facades/voice-session.facade';
import { loadVoiceSettingsFromStorage, saveVoiceSettingsToStorage } from '../../infrastructure/util/voice-settings-storage.util';
import { VoiceConnectionFacade } from '../../../../domains/voice-connection';
import { VoicePlaybackService } from '../../../../domains/voice-connection';
import { ScreenShareFacade, ScreenShareQuality } from '../../../../domains/screen-share';
import { UsersActions } from '../../../../store/users/users.actions';
import { selectCurrentUser } from '../../../../store/users/users.selectors';
import { DebugConsoleComponent, ScreenShareQualityDialogComponent } from '../../../../shared';
import { ThemeNodeDirective } from '../../../../domains/theme';

@Component({
  selector: 'app-floating-voice-controls',
  standalone: true,
  imports: [
    CommonModule,
    NgIcon,
    DebugConsoleComponent,
    ScreenShareQualityDialogComponent,
    ThemeNodeDirective
  ],
  viewProviders: [
    provideIcons({
      lucideMic,
      lucideMicOff,
      lucideMonitor,
      lucideMonitorOff,
      lucidePhoneOff,
      lucideHeadphones,
      lucideArrowLeft
    })
  ],
  templateUrl: './floating-voice-controls.component.html'
})
/**
 * Floating voice controls displayed when the user navigates away from the voice-connected server.
 * Provides mute, deafen, screen-share, and disconnect actions in a compact overlay.
 */
export class FloatingVoiceControlsComponent implements OnInit {
  private readonly webrtcService = inject(VoiceConnectionFacade);
  private readonly screenShareService = inject(ScreenShareFacade);
  private readonly voiceSessionService = inject(VoiceSessionFacade);
  private readonly voicePlayback = inject(VoicePlaybackService);
  private readonly store = inject(Store);

  currentUser = this.store.selectSignal(selectCurrentUser);

  // Voice state from services
  showFloatingControls = this.voiceSessionService.showFloatingControls;
  voiceSession = this.voiceSessionService.voiceSession;

  isConnected = computed(() => this.webrtcService.isVoiceConnected());
  isMuted = signal(false);
  isDeafened = signal(false);
  isScreenSharing = this.screenShareService.isScreenSharing;
  includeSystemAudio = signal(false);
  screenShareQuality = signal<ScreenShareQuality>('balanced');
  askScreenShareQuality = signal(true);
  showScreenShareQualityDialog = signal(false);

  /** Sync local mute/deafen state from the WebRTC service on init. */
  ngOnInit(): void {
    // Sync mute/deafen state from webrtc service
    this.isMuted.set(this.webrtcService.isMuted());
    this.isDeafened.set(this.webrtcService.isDeafened());
    this.syncScreenShareSettings();

    const settings = loadVoiceSettingsFromStorage();

    this.voicePlayback.updateOutputVolume(settings.outputVolume / 100);
    this.voicePlayback.updateDeafened(this.isDeafened());

    if (settings.outputDevice) {
      this.voicePlayback.applyOutputDevice(settings.outputDevice);
    }
  }

  /** Navigate back to the voice-connected server. */
  navigateToServer(): void {
    this.voiceSessionService.navigateToVoiceServer();
  }

  /** Toggle microphone mute and broadcast the updated voice state. */
  toggleMute(): void {
    this.isMuted.update((current) => !current);
    this.webrtcService.toggleMute(this.isMuted());

    // Broadcast mute state change
    this.webrtcService.broadcastMessage({
      type: 'voice-state',
      oderId: this.currentUser()?.oderId || this.currentUser()?.id,
      displayName: this.currentUser()?.displayName || 'User',
      voiceState: {
        isConnected: this.isConnected(),
        isMuted: this.isMuted(),
        isDeafened: this.isDeafened()
      }
    });
  }

  /** Toggle deafen state (muting audio output) and broadcast the updated voice state. */
  toggleDeafen(): void {
    this.isDeafened.update((current) => !current);
    this.webrtcService.toggleDeafen(this.isDeafened());
    this.voicePlayback.updateDeafened(this.isDeafened());

    // When deafening, also mute
    if (this.isDeafened() && !this.isMuted()) {
      this.isMuted.set(true);
      this.webrtcService.toggleMute(true);
    }

    // Broadcast deafen state change
    this.webrtcService.broadcastMessage({
      type: 'voice-state',
      oderId: this.currentUser()?.oderId || this.currentUser()?.id,
      displayName: this.currentUser()?.displayName || 'User',
      voiceState: {
        isConnected: this.isConnected(),
        isMuted: this.isMuted(),
        isDeafened: this.isDeafened()
      }
    });
  }

  /** Toggle screen sharing on or off. */
  async toggleScreenShare(): Promise<void> {
    if (this.isScreenSharing()) {
      this.screenShareService.stopScreenShare();
    } else {
      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 from the voice session entirely, cleaning up all voice state. */
  disconnect(): void {
    // Stop voice heartbeat
    this.webrtcService.stopVoiceHeartbeat();

    // Broadcast voice disconnect
    this.webrtcService.broadcastMessage({
      type: 'voice-state',
      oderId: this.currentUser()?.oderId || this.currentUser()?.id,
      displayName: this.currentUser()?.displayName || 'User',
      voiceState: {
        isConnected: false,
        isMuted: false,
        isDeafened: false
      }
    });

    // Stop screen sharing if active
    if (this.isScreenSharing()) {
      this.screenShareService.stopScreenShare();
    }

    // Disable voice
    this.webrtcService.disableVoice();
    this.voicePlayback.teardownAll();
    this.voicePlayback.updateDeafened(false);

    // Update user voice state in store
    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 }
      }));
    }

    // End voice session
    this.voiceSessionService.endSession();

    // Reset local state
    this.isMuted.set(false);
    this.isDeafened.set(false);
  }

  /** Return the CSS classes for the compact control button based on active state. */
  getCompactButtonClass(isActive: boolean): string {
    const base = 'inline-flex h-7 w-7 items-center justify-center rounded-md border transition-colors';

    if (isActive) {
      return base + ' border-destructive/30 bg-destructive/10 text-destructive hover:bg-destructive/15';
    }

    return base + ' border-border bg-card text-foreground hover:bg-secondary/70';
  }

  /** Return the CSS classes for the compact screen-share button. */
  getCompactScreenShareClass(): string {
    const base = 'inline-flex h-7 w-7 items-center justify-center rounded-md border transition-colors';

    if (this.isScreenSharing()) {
      return base + ' border-primary/20 bg-primary/10 text-primary hover:bg-primary/15';
    }

    return base + ' border-border bg-card text-foreground hover:bg-secondary/70';
  }

  /** Return the CSS classes for the mute toggle button. */
  getMuteButtonClass(): string {
    const base = 'inline-flex h-10 w-10 items-center justify-center rounded-md border transition-colors';

    if (this.isMuted()) {
      return base + ' border-destructive/30 bg-destructive/10 text-destructive hover:bg-destructive/15';
    }

    return base + ' border-border bg-card text-foreground hover:bg-secondary/70';
  }

  /** Return the CSS classes for the deafen toggle button. */
  getDeafenButtonClass(): string {
    const base = 'inline-flex h-10 w-10 items-center justify-center rounded-md border transition-colors';

    if (this.isDeafened()) {
      return base + ' border-destructive/30 bg-destructive/10 text-destructive hover:bg-destructive/15';
    }

    return base + ' border-border bg-card text-foreground hover:bg-secondary/70';
  }

  /** Return the CSS classes for the screen-share toggle button. */
  getScreenShareButtonClass(): string {
    const base = 'inline-flex h-10 w-10 items-center justify-center rounded-md border transition-colors';

    if (this.isScreenSharing()) {
      return base + ' border-primary/20 bg-primary/10 text-primary hover:bg-primary/15';
    }

    return base + ' border-border bg-card text-foreground hover:bg-secondary/70';
  }

  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> {
    try {
      await this.screenShareService.startScreenShare({
        includeSystemAudio: this.includeSystemAudio(),
        quality
      });
    } catch (_error) {
      // Screen share request was denied or failed
    }
  }
}
