import type { CropBox, ExportFormat, VideoDimensions } from "@/lib/trimmer-types";

export interface ProcessVideoInWorkerOptions {
  file: File;
  trimStart: number;
  trimEnd: number;
  cropBox: CropBox;
  displaySize: VideoDimensions;
  videoSize: VideoDimensions;
  exportFormat: ExportFormat;
  onProgress: (percent: number) => void;
  onLog?: (message: string) => void;
}

let worker: Worker | null = null;
let initPromise: Promise<void> | null = null;

function getWorker(): Worker {
  if (!worker) {
    worker = new Worker(
      new URL("../workers/ffmpeg-trim.worker.ts", import.meta.url)
    );
  }
  return worker;
}

export function preloadFfmpegWorker(): Promise<void> {
  if (initPromise) return initPromise;

  initPromise = new Promise((resolve, reject) => {
    const w = getWorker();

    const handleMessage = (event: MessageEvent) => {
      const { type } = event.data as { type: string };
      if (type === "ready") {
        w.removeEventListener("message", handleMessage);
        resolve();
      }
      if (type === "error") {
        w.removeEventListener("message", handleMessage);
        reject(new Error("FFmpeg worker failed to initialize"));
      }
    };

    w.addEventListener("message", handleMessage);
    w.postMessage({ type: "init" });
  });

  return initPromise;
}

export function isFfmpegWorkerReady(): boolean {
  return initPromise !== null;
}

export async function processTrimmedVideoInWorker(
  options: ProcessVideoInWorkerOptions
): Promise<Blob> {
  await preloadFfmpegWorker();

  const {
    file,
    trimStart,
    trimEnd,
    cropBox,
    displaySize,
    videoSize,
    exportFormat,
    onProgress,
    onLog,
  } = options;

  const fileBuffer = await file.arrayBuffer();

  return new Promise((resolve, reject) => {
    const w = getWorker();

    const handleMessage = (event: MessageEvent) => {
      const data = event.data as {
        type: string;
        percent?: number;
        message?: string;
        buffer?: ArrayBuffer;
        mime?: string;
      };

      if (data.type === "progress" && typeof data.percent === "number") {
        onProgress(data.percent);
      }

      if (data.type === "log" && data.message) {
        onLog?.(data.message);
      }

      if (data.type === "complete" && data.buffer && data.mime) {
        w.removeEventListener("message", handleMessage);
        resolve(new Blob([data.buffer], { type: data.mime }));
      }

      if (data.type === "error") {
        w.removeEventListener("message", handleMessage);
        reject(new Error(data.message ?? "Processing failed"));
      }
    };

    w.addEventListener("message", handleMessage);
    w.postMessage(
      {
        type: "process",
        fileBuffer,
        fileName: file.name,
        trimStart,
        trimEnd,
        cropBox,
        displaySize,
        videoSize,
        exportFormat,
      },
      [fileBuffer]
    );
  });
}

export function terminateFfmpegWorker(): void {
  worker?.terminate();
  worker = null;
  initPromise = null;
}
