import { Component, inject, ChangeDetectionStrategy } from '@angular/core';
import { NgClass } from '@angular/common';
import {
  LocalTrack,
  VideoTrack,
  RemoteTrackPublication,
  VideoQuality,
} from 'livekit-client';
import { TrackComponent } from '../track/track.component';
import { MatDialog } from '@angular/material/dialog';
import { TestFeedService } from 'src/app/services/test-feed.service';
import { InfoDialogComponent } from '../dialogs/info-dialog/info-dialog.component';
import { ProcessorDialogComponent } from '../dialogs/processor-dialog/processor-dialog.component';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatSelectModule } from '@angular/material/select';

@Component({
  selector: 'app-video-track',
  templateUrl: './video-track.component.html',
  styleUrl: './video-track.component.css',
  changeDetection: ChangeDetectionStrategy.Eager,
  imports: [NgClass, MatIconModule, MatTooltipModule, MatFormFieldModule, MatSelectModule],
})
export class VideoTrackComponent extends TrackComponent {
  muteVideoIcon: string = 'videocam';
  maxVideoQuality: string;

  videoZoom = false;

  // Processor state
  processor: any;
  mode: 'disabled' | 'background-blur' | 'virtual-background' | undefined =
    'virtual-background';
  backgroundType: 'image' | 'screen' = 'image';
  tracking: boolean = false;
  scale: number = 1;
  horizontalPosition: number = 0;
  blurRadius: number = 10;
  processorEnabled: boolean = false;
  screenShareTrack: MediaStreamTrack | undefined;

  segmentationMethod: 'mediapipe' | 'chroma' = 'mediapipe';
  modelAssetPath: string = 'https://storage.googleapis.com/mediapipe-models/image_segmenter/selfie_segmenter/float16/latest/selfie_segmenter.tflite';
  chromaKey = {
    autoDetect: true,
    autoDetectThreshold: [70, 70, 70] as [number, number, number],
    hueRange: [60, 130] as [number, number],
    saturationRange: [50, 255] as [number, number],
    valueRange: [50, 255] as [number, number],
    sampleRegion: { startX: 0.05, endX: 0.2, startY: 0.08, endY: 0.25 },
    autoDetectFrameInterval: 30
  };

  private dialog = inject(MatDialog);

  constructor(
    protected override testFeedService: TestFeedService,
  ) {
    super(testFeedService);
  }

  async muteUnmuteVideo() {
    if (this._track?.isMuted) {
      this.muteVideoIcon = 'videocam';
      await (this._track as LocalTrack).unmute();
    } else {
      this.muteVideoIcon = 'videocam_off';
      await (this._track as LocalTrack).mute();
    }
  }

  async onQualityChange() {
    let videoQuality: VideoQuality;
    switch (this.maxVideoQuality) {
      case 'LOW':
        videoQuality = VideoQuality.LOW;
        break;
      case 'MEDIUM':
        videoQuality = VideoQuality.MEDIUM;
        break;
      case 'HIGH':
        videoQuality = VideoQuality.HIGH;
        break;
      default:
        videoQuality = VideoQuality.HIGH;
    }
    await (this.trackPublication as RemoteTrackPublication).setVideoQuality(
      videoQuality
    );
  }

  openInfoDialog() {
    const updateFunction = async (): Promise<string> => {
      const videoLayers: any[] = [];
      let stats = await (this._track! as VideoTrack).getRTCStatsReport();
      let codecs = new Map();
      stats?.forEach((report) => {
        if (report.type === 'codec') {
          // Store for matching with codecId in 'outbound-rtp' or 'inbound-rtp' reports
          codecs.set(report.id, report);
        }
        if (report.type === 'outbound-rtp' || report.type === 'inbound-rtp') {
          videoLayers.push({
            codecId: report.codecId,
            scalabilityMode: report.scalabilityMode,
            rid: report.rid,
            active: report.active,
            frameWidth: report.frameWidth,
            frameHeight: report.frameHeight,
            framesPerSecond: report.framesPerSecond,
            bytesReceived: report.bytesReceived,
            bytesSent: report.bytesSent,
          });
        }
      });
      videoLayers.forEach((layer) => {
        if (codecs.has(layer.codecId)) {
          layer.codec = codecs.get(layer.codecId).mimeType;
        }
      });
      return JSON.stringify(videoLayers, null, 2);
    };
    this.dialog.open(InfoDialogComponent, {
      data: {
        title: 'Video Track Layers Info',
        subtitle: this.finalElementRefId,
        updateFunction,
        updateInterval: 700,
      },
    });
  }

  openProcessorDialog() {
    this.dialog.open(ProcessorDialogComponent, {
      data: {
        videoTrack: this,
      },
      width: '1400px',
      maxWidth: '95vw',
      maxHeight: '95vh',
    });
  }

  toggleVideoZoom() {
    this.videoZoom = !this.videoZoom;
    let newWidth = this.videoZoom ? '1500px' : '120px';
    this.elementRef.nativeElement.style.width = newWidth;
  }
}
