/* eslint-disable @typescript-eslint/member-ordering, */
import {
  Injectable,
  signal,
  computed,
  inject
} from '@angular/core';
import { Store } from '@ngrx/store';
import { RoomsActions } from '../../../../store/rooms/rooms.actions';
import { buildVoiceSessionRoom, isViewingVoiceSessionServer } from '../../domain/logic/voice-session.logic';
import type { VoiceSessionInfo } from '../../domain/models/voice-session.model';

/**
 * Tracks the user's current voice session across client-side
 * navigation so that floating voice controls remain visible when
 * the user is browsing a different server or view.
 *
 * This service is purely a UI-state tracker - actual WebRTC
 * voice management lives in {@link WebRTCService} and its managers.
 */
@Injectable({ providedIn: 'root' })
export class VoiceSessionFacade {
  private readonly store = inject(Store);

  /** Current voice session metadata, or `null` when disconnected. */
  private readonly _voiceSession = signal<VoiceSessionInfo | null>(null);

  /** Whether the user is currently viewing the voice-connected server. */
  private readonly _isViewingVoiceServer = signal<boolean>(true);

  /** Reactive read-only voice session. */
  readonly voiceSession = computed(() => this._voiceSession());

  /** Reactive flag: is the user's current view the voice server? */
  readonly isViewingVoiceServer = computed(() => this._isViewingVoiceServer());

  /**
   * Whether the floating voice-controls overlay should be visible.
   * `true` when a voice session is active AND the user is viewing
   * a different server.
   */
  readonly showFloatingControls = computed(
    () => this._voiceSession() !== null && !this._isViewingVoiceServer()
  );

  /**
   * Begin tracking a voice session.
   * Called when the user joins a voice channel.
   *
   * @param sessionInfo - Metadata describing the voice-connected server/channel.
   */
  startSession(sessionInfo: VoiceSessionInfo): void {
    this._voiceSession.set(sessionInfo);
    this._isViewingVoiceServer.set(true);
  }

  /**
   * Stop tracking the voice session.
   * Called when the user disconnects from voice.
   */
  endSession(): void {
    this._voiceSession.set(null);
    this._isViewingVoiceServer.set(true);
  }

  /**
   * Manually flag whether the user is currently viewing the
   * voice-connected server.
   *
   * @param isViewing - `true` if the user's current view is the voice server.
   */
  setViewingVoiceServer(isViewing: boolean): void {
    this._isViewingVoiceServer.set(isViewing);
  }

  /**
   * Compare the given server ID to the voice session's server and
   * update the {@link isViewingVoiceServer} flag accordingly.
   *
   * @param currentServerId - ID of the server the user is currently viewing.
   */
  checkCurrentRoute(currentServerId: string | null): void {
    this._isViewingVoiceServer.set(
      isViewingVoiceSessionServer(this._voiceSession(), currentServerId)
    );
  }

  /**
   * Navigate the user back to the voice-connected server by
   * dispatching a `viewServer` action.
   */
  navigateToVoiceServer(): void {
    const session = this._voiceSession();

    if (!session)
      return;

    this.store.dispatch(
      RoomsActions.viewServer({
        room: buildVoiceSessionRoom(session)
      })
    );

    this._isViewingVoiceServer.set(true);
  }

  /**
   * Return the server ID of the active voice session, or `null`
   * if the user is not in a voice channel.
   */
  getVoiceServerId(): string | null {
    return this._voiceSession()?.serverId ?? null;
  }
}
