/* eslint-disable @typescript-eslint/member-ordering, @typescript-eslint/no-unused-vars */
import {
  Component,
  inject,
  signal,
  ElementRef,
  ViewChild,
  OnDestroy,
  effect
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { Store } from '@ngrx/store';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { Subscription } from 'rxjs';
import {
  lucideMaximize,
  lucideMinimize,
  lucideX,
  lucideMonitor
} from '@ng-icons/lucide';

import { ScreenShareFacade } from '../../application/facades/screen-share.facade';
import { selectOnlineUsers } from '../../../../store/users/users.selectors';
import { User } from '../../../../shared-kernel';
import { DEFAULT_VOLUME } from '../../../../core/constants';
import { VoicePlaybackService } from '../../../../domains/voice-connection';

@Component({
  selector: 'app-screen-share-viewer',
  standalone: true,
  imports: [CommonModule, NgIcon],
  viewProviders: [
    provideIcons({
      lucideMaximize,
      lucideMinimize,
      lucideX,
      lucideMonitor
    })
  ],
  templateUrl: './screen-share-viewer.component.html'
})
/**
 * Displays a local or remote screen-share stream in a video player.
 * Supports fullscreen toggling, volume control, and viewer focus events.
 */
export class ScreenShareViewerComponent implements OnDestroy {
  @ViewChild('screenVideo') videoRef!: ElementRef<HTMLVideoElement>;

  private readonly screenShareService = inject(ScreenShareFacade);
  private readonly voicePlayback = inject(VoicePlaybackService);
  private readonly store = inject(Store);
  private remoteStreamSub: Subscription | null = null;

  onlineUsers = this.store.selectSignal(selectOnlineUsers);

  activeScreenSharer = signal<User | null>(null);
  // Track the userId we're currently watching (for detecting when they stop sharing)
  private watchingUserId = signal<string | null>(null);
  isFullscreen = signal(false);
  hasStream = signal(false);
  isLocalShare = signal(false);
  screenVolume = signal(DEFAULT_VOLUME);

  private streamSubscription: (() => void) | null = null;
  private viewerFocusHandler = (evt: CustomEvent<{ userId: string }>) => {
    try {
      const userId = evt.detail?.userId;

      if (!userId)
        return;

      const stream = this.screenShareService.getRemoteScreenShareStream(userId);
      const user = this.onlineUsers().find((onlineUser) => onlineUser.id === userId || onlineUser.oderId === userId) || null;

      if (stream && stream.getVideoTracks().length > 0) {
        if (user) {
          this.setRemoteStream(stream, user);
        } else if (this.videoRef) {
          this.videoRef.nativeElement.srcObject = stream;
          this.videoRef.nativeElement.volume = 0;
          this.videoRef.nativeElement.muted = true;
          this.hasStream.set(true);
          this.activeScreenSharer.set(null);
          this.watchingUserId.set(userId);
          this.screenVolume.set(this.voicePlayback.getUserVolume(userId));
          this.isLocalShare.set(false);
        }
      }
    } catch (_error) {
      // Failed to focus viewer on user stream
    }
  };

  constructor() {
    // React to screen share stream changes
    effect(() => {
      const screenStream = this.screenShareService.screenStream();

      if (screenStream && this.videoRef) {
        // Local share: always mute to avoid audio feedback
        this.videoRef.nativeElement.srcObject = screenStream;
        this.videoRef.nativeElement.volume = 0;
        this.videoRef.nativeElement.muted = true;
        this.isLocalShare.set(true);
        this.hasStream.set(true);
      } else if (this.videoRef) {
        this.videoRef.nativeElement.srcObject = null;
        this.isLocalShare.set(false);
        this.hasStream.set(false);
      }
    });

    // Watch for when the user we're watching stops sharing
    effect(() => {
      const watchingId = this.watchingUserId();
      const isWatchingRemote = this.hasStream() && !this.isLocalShare();

      // Only check if we're actually watching a remote stream
      if (!watchingId || !isWatchingRemote)
        return;

      const users = this.onlineUsers();
      const watchedUser = users.find(user => user.id === watchingId || user.oderId === watchingId);

      // If the user is no longer sharing (screenShareState.isSharing is false), stop watching
      if (watchedUser && watchedUser.screenShareState?.isSharing === false) {
        this.stopWatching();
        return;
      }

      // Also check if the stream's video tracks are still available
      const stream = this.screenShareService.getRemoteScreenShareStream(watchingId);
      const hasActiveVideo = stream?.getVideoTracks().some(track => track.readyState === 'live');

      if (!hasActiveVideo) {
        // Stream or video tracks are gone - stop watching
        this.stopWatching();
      }
    });

    // Subscribe to remote streams with video (screen shares)
    // NOTE: We no longer auto-display remote streams. Users must click "Live" to view.
    // This subscription is kept for potential future use (e.g., tracking available streams)
    this.remoteStreamSub = this.screenShareService.onRemoteStream.subscribe(({ peerId }) => {
      if (peerId !== this.watchingUserId() || this.isLocalShare()) {
        return;
      }

      const stream = this.screenShareService.getRemoteScreenShareStream(peerId);
      const hasActiveVideo = stream?.getVideoTracks().some((track) => track.readyState === 'live') ?? false;

      if (!hasActiveVideo) {
        this.stopWatching();
      }
    });

    // Listen for focus events dispatched by other components
    window.addEventListener('viewer:focus', this.viewerFocusHandler as EventListener);
  }

  ngOnDestroy(): void {
    if (this.isFullscreen()) {
      this.exitFullscreen();
    }

    // Cleanup subscription
    this.remoteStreamSub?.unsubscribe();

    // Remove event listener
    window.removeEventListener('viewer:focus', this.viewerFocusHandler as EventListener);
  }

  /** Toggle between fullscreen and windowed display. */
  toggleFullscreen(): void {
    if (this.isFullscreen()) {
      this.exitFullscreen();
    } else {
      this.enterFullscreen();
    }
  }

  /** Enter fullscreen mode, requesting browser fullscreen if available. */
  enterFullscreen(): void {
    this.isFullscreen.set(true);

    // Request browser fullscreen if available
    if (this.videoRef?.nativeElement.requestFullscreen) {
      this.videoRef.nativeElement.requestFullscreen().catch(() => {
        // Fallback to CSS fullscreen
      });
    }
  }

  /** Exit fullscreen mode. */
  exitFullscreen(): void {
    this.isFullscreen.set(false);

    if (document.fullscreenElement) {
      document.exitFullscreen().catch(() => {});
    }
  }

  /** Stop the local screen share and reset viewer state. */
  stopSharing(): void {
    this.screenShareService.stopScreenShare();
    this.activeScreenSharer.set(null);
    this.hasStream.set(false);
    this.isLocalShare.set(false);
  }

  /** Stop watching a remote stream and reset the viewer. */
  // Stop watching a remote stream (for viewers)
  stopWatching(): void {
    if (this.videoRef) {
      this.videoRef.nativeElement.srcObject = null;
    }

    this.activeScreenSharer.set(null);
    this.watchingUserId.set(null);
    this.hasStream.set(false);
    this.isLocalShare.set(false);

    if (this.isFullscreen()) {
      this.exitFullscreen();
    }
  }

  /** Attach and play a remote peer's screen-share stream. */
  // Called by parent when a remote peer starts sharing
  setRemoteStream(stream: MediaStream, user: User): void {
    this.activeScreenSharer.set(user);
    this.watchingUserId.set(user.id || user.oderId || null);
    this.isLocalShare.set(false);
    this.screenVolume.set(this.voicePlayback.getUserVolume(user.id || user.oderId || ''));

    if (this.videoRef) {
      const el = this.videoRef.nativeElement;

      el.srcObject = stream;
      // Keep the viewer muted so screen-share audio only plays once via VoicePlaybackService.
      el.muted = true;
      el.volume = 0;
      el.play().catch(() => {});

      this.hasStream.set(true);
    }
  }

  /** Attach and play the local user's screen-share stream (always muted). */
  // Called when local user starts sharing
  setLocalStream(stream: MediaStream, user: User): void {
    this.activeScreenSharer.set(user);
    this.isLocalShare.set(true);

    if (this.videoRef) {
      this.videoRef.nativeElement.srcObject = stream;
      // Always mute local share playback
      this.videoRef.nativeElement.volume = 0;
      this.videoRef.nativeElement.muted = true;
      this.hasStream.set(true);
    }
  }

  /** Handle volume slider changes, applying only to remote streams. */
  onScreenVolumeChange(event: Event): void {
    const input = event.target as HTMLInputElement;
    const val = Math.max(0, Math.min(200, parseInt(input.value, 10)));

    this.screenVolume.set(val);

    if (!this.isLocalShare()) {
      const userId = this.watchingUserId();

      if (userId) {
        this.voicePlayback.setUserVolume(userId, val);
      }
    }
  }
}
