// Lazily loads the FFmpeg.wasm singleton. Subsequent `loadFFmpeg` calls
// return the same wrapper, so we only pay the download cost once per page.
//
// We serve ffmpeg-core from /public/ffmpeg/ so the wasm + worker JS are
// same-origin. This is important because the page sets
// Cross-Origin-Embedder-Policy: require-corp (for SharedArrayBuffer), and
// loading core from unpkg.com fails under that policy.

const CORE_BASE_DEFAULT = '/ffmpeg';

let ffmpegInstance: unknown = null;
let loadingPromise: Promise<unknown> | null = null;

export interface FFmpegWrapper {
  ffmpeg: any;
  fetchFile: (input: Blob | string) => Promise<Uint8Array>;
}

export async function loadFFmpeg(
  onLog?: (msg: string) => void,
): Promise<FFmpegWrapper> {
  if (ffmpegInstance) return ffmpegInstance as FFmpegWrapper;
  if (loadingPromise) return loadingPromise as Promise<FFmpegWrapper>;

  loadingPromise = (async () => {
    const [{ FFmpeg }, util] = await Promise.all([
      import('@ffmpeg/ffmpeg'),
      import('@ffmpeg/util'),
    ]);
    const ff = new FFmpeg();
    if (onLog) ff.on('log', ({ message }: { message: string }) => onLog(message));
    const baseURL = CORE_BASE_DEFAULT;
    await ff.load({
      coreURL: `${baseURL}/ffmpeg-core.js`,
      wasmURL: `${baseURL}/ffmpeg-core.wasm`,
      // Note: we deliberately do NOT pass workerURL here. The @ffmpeg/ffmpeg
      // v0.12.x package ships its own bundled worker module which knows
      // how to talk to the wasm. Overriding it with our local file is
      // unnecessary and breaks loading in some browsers.
    });
    const wrapper: FFmpegWrapper = { ffmpeg: ff, fetchFile: util.fetchFile };
    ffmpegInstance = wrapper;
    return wrapper;
  })();

  return loadingPromise as Promise<FFmpegWrapper>;
}

export function resetFFmpeg(): void {
  ffmpegInstance = null;
  loadingPromise = null;
}