import {ChangeDetectorRef, Component, HostListener, inject, input} from '@angular/core';
import {
  TUI_BREAKPOINT,
  TuiAppearance,
  TuiButton,
  TuiDialog,
  TuiGroup,
  TuiIcon,
  TuiScrollbarDirective,
  TuiTextfield
} from '@taiga-ui/core';
import {TranslatePipe} from '@ngx-translate/core';
import {ServiceManager} from '../../../service-manager';
import {MessageBoxViewModel} from './message-box-viewmodel';
import {FormsModule} from '@angular/forms';
import {v4 as uuidv4} from 'uuid';
import {Masonry} from '../masonry/masonry';
import {Oimg} from '../oimg/oimg';
import {FileData} from '@chatenium/chatenium-sdk/domain/fileUploadService.schema';
import {TuiTextarea, TuiTextareaComponent} from '@taiga-ui/kit';

@Component({
  selector: 'message-box',
  imports: [
    TuiAppearance,
    TranslatePipe,
    TuiScrollbarDirective,
    TuiGroup,
    TuiIcon,
    TuiButton,
    FormsModule,
    TuiDialog,
    Oimg,
    Masonry,
    TuiTextfield,
    TuiTextarea
  ],
  templateUrl: './message-box.html',
  styleUrl: './message-box.scss',
})
export class MessageBox {
  viewModel = input.required<MessageBoxViewModel>()

  breakpoint = inject(TUI_BREAKPOINT)
  cdr = inject(ChangeDetectorRef)

  textareaHeight = 25
  messageBoxRadius = 200

  private dragCounter = 0;
  isDraggingOverWindow = false;

  @HostListener('window:dragenter', ['$event'])
  onDragEnter(event: DragEvent) {
    event.preventDefault();
    this.dragCounter++;

    if (this.dragCounter === 1) {
      this.isDraggingOverWindow = true;
      console.log("Drag entered the window area");
    }
  }

  @HostListener('window:dragleave', ['$event'])
  onDragLeave(event: DragEvent) {
    event.preventDefault();
    this.dragCounter--;

    if (this.dragCounter === 0) {
      this.isDraggingOverWindow = false;
      console.log("Drag left the window completely");
    }
  }

  onDragOver(event: DragEvent) {
    // This is the "magic" line that enables the drop event to fire
    event.preventDefault();
    event.stopPropagation();
  }

  onDrop(event: DragEvent) {
    event.preventDefault();
    event.stopPropagation();

    const files = event.dataTransfer?.files;
    if (files) this.processFiles(files)
    this.isDraggingOverWindow = false
    this.cdr.detectChanges();
  }

  onTextAreaInput(e: HTMLTextAreaElement) {
    const calculatedHeight = e.value.split(/\r?\n/).length * 25
    const calculatedRadius = (200 - this.textareaHeight)
    this.textareaHeight = calculatedHeight > 180 ? 180 : calculatedHeight
    this.messageBoxRadius = calculatedRadius < 30 ? 30 : calculatedRadius
  }

  handleFileInput(event: any) {
    this.processFiles(event.target.files)
  }

  sendMessageWithCaption() {
    this.viewModel().onMessageSend(this.viewModel().message(), this.viewModel().files())
    this.viewModel().message.set("")
    this.viewModel().files.set([])
    this.viewModel().dialogOpen.set(false)
  }

  handleEnterKeydown(e: any) {
    e.preventDefault()
    return false
  }

  filterPictureVideo(files: FileDataWithPreview[]) {
    return files.filter(f => f.type == "image")
  }

  async processFiles(fileList: FileList) {
    for (let i = 0; i < fileList.length; i++) {
      const file = fileList[i];
      const type = file.type.split("/").shift() ?? ""
      let blob = ""
      let thumbnailBlob = undefined
      let height = 0
      let width = 0

      console.log(type)

      blob = URL.createObjectURL(file)
      if (type == "image") {
        const imgData = await fetchImageDimensions(file)
        console.log(imgData)
        height = imgData.height
        width = imgData.width
      } else if (type == "video") {
        const videoData = await processVideo(file)
        thumbnailBlob = videoData.thumbnailBlob
        height = videoData.height
        width = videoData.width
      }

      this.viewModel().files().push({
        fileId: uuidv4(),
        data: file,
        name: file.name,
        type: type,
        extension: file.name.split(".").pop() ?? "",
        blob: blob,
        height: height,
        width: width,
        videoThumbnail: thumbnailBlob,
      })
    }
    this.viewModel().dialogOpen.set(true)

    function fetchImageDimensions(file: File): Promise<{ height: number, width: number }> {
      return new Promise((resolve, reject) => {
        const img = new Image();
        const objectUrl = URL.createObjectURL(file);

        img.onload = () => {
          console.log("Loaded image")
          resolve({
            width: img.naturalWidth,
            height: img.naturalHeight,
          });
        };

        img.onerror = (err) => {
          URL.revokeObjectURL(objectUrl);
          console.error("Error loading image:", err);
          reject(err);
        };

        img.src = objectUrl;
      });
    }

    async function processVideo(file: File): Promise<{ thumbnailBlob: string, height: number, width: number }> {
      const objectUrl = URL.createObjectURL(file);
      const video = document.createElement('video');
      video.src = objectUrl;
      video.preload = 'metadata'; // Ensure metadata is loaded
      video.muted = true;
      video.playsInline = true;

      return new Promise((resolve) => {
        video.addEventListener('loadeddata', () => {
          // Step 1: Seek to a tiny bit past 0 to ensure a frame is available
          video.currentTime = 0.1;
        });

        video.addEventListener('seeked', async () => {
          // Step 2: Now that the seek is done, the frame is ready
          const canvas = document.createElement('canvas');
          canvas.width = video.videoWidth;
          canvas.height = video.videoHeight;

          const ctx = canvas.getContext('2d');
          ctx!.drawImage(video, 0, 0, canvas.width, canvas.height);

          // Clean up: Convert directly to blob to avoid double-processing
          canvas.toBlob((blob) => {
            const thumbnailBlobUrl = URL.createObjectURL(blob!);

            // Revoke the original video URL to save memory
            URL.revokeObjectURL(objectUrl);

            resolve({
              thumbnailBlob: thumbnailBlobUrl,
              height: video.videoHeight,
              width: video.videoWidth,
            });
          }, 'image/jpeg', 0.8);
        }, { once: true }); // Only trigger once
      });
    }
  }

  protected readonly console = console;
}

/**
 * All the extra data for client-side rendering. (With finished messages these are generated on the server)
 */
export interface FileDataWithPreview extends FileData {
  blob: string;
  videoThumbnail?: string;
  height: number;
  width: number;
}
