import { FFmpeg } from "@ffmpeg/ffmpeg";
import { fetchFile, toBlobURL } from "@ffmpeg/util";

let ffmpegInstance: FFmpeg | null = null;
let loadPromise: Promise<void> | null = null;

async function getFfmpeg(): Promise<FFmpeg> {
  if (ffmpegInstance?.loaded) return ffmpegInstance;
  if (!loadPromise) {
    loadPromise = (async () => {
      const ffmpeg = new FFmpeg();
      const baseURL = "https://unpkg.com/@ffmpeg/core@0.12.6/dist/esm";
      await ffmpeg.load({
        coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, "text/javascript"),
        wasmURL: await toBlobURL(
          `${baseURL}/ffmpeg-core.wasm`,
          "application/wasm"
        ),
      });
      ffmpegInstance = ffmpeg;
    })();
  }
  await loadPromise;
  return ffmpegInstance!;
}

const MAX_VIDEO_EDGE = 1080;

/**
 * Transcode to MP4 H.264 (Instagram-style) — lazy-loads ffmpeg.wasm on first use.
 */
export async function optimizeVideoToMp4(
  file: File,
  onProgress?: (pct: number) => void
): Promise<File> {
  if (!file.type.startsWith("video/")) return file;

  if (
    file.type === "video/mp4" &&
    file.size < 40 * 1024 * 1024 &&
    !file.name.toLowerCase().includes(".mov")
  ) {
    return file;
  }

  const ffmpeg = await getFfmpeg();

  if (onProgress) {
    ffmpeg.on("progress", ({ progress }) => {
      onProgress(Math.min(99, Math.round((progress ?? 0) * 100)));
    });
  }

  const inputName = "input" + (file.name.match(/\.\w+$/)?.[0] || ".mp4");
  const outputName = "output.mp4";

  await ffmpeg.writeFile(inputName, await fetchFile(file));

  await ffmpeg.exec([
    "-i",
    inputName,
    "-vf",
    `scale='min(${MAX_VIDEO_EDGE},iw)':-2`,
    "-c:v",
    "libx264",
    "-preset",
    "fast",
    "-crf",
    "28",
    "-c:a",
    "aac",
    "-b:a",
    "128k",
    "-movflags",
    "+faststart",
    "-y",
    outputName,
  ]);

  const data = await ffmpeg.readFile(outputName);
  await ffmpeg.deleteFile(inputName);
  await ffmpeg.deleteFile(outputName);

  const blob = new Blob([data as BlobPart], { type: "video/mp4" });
  const baseName = file.name.replace(/\.[^.]+$/, "") || "video";
  onProgress?.(100);
  return new File([blob], `${baseName}.mp4`, { type: "video/mp4" });
}
