import React from "react";
import { renderMediaOnWeb, canRenderMediaOnWeb } from "@remotion/web-renderer";
import { JobVideoContent } from "../JobVideo";
import type { JobScript, JobTiming } from "../job/script";

/**
 * Browser-side WebCodecs render of the scripted promo composition.
 *
 * This entry is bundled on demand by scripts/webrender.mjs (esbuild) and
 * loaded by the admin UI's WebRenderPanel. It receives props from the page
 * via a global injected by the panel:
 *
 *   window.__PROMO_WEBRENDER__ = {
 *     script, schedule, durationInFrames,   // JobVideoContent props
 *     format: "landscape" | "vertical",
 *     jobId, staticOrigin
 *   }
 *
 * The render itself needs no server: frames are drawn to a canvas and encoded
 * with WebCodecs + Mediabunny — no ffmpeg anywhere. The resulting mp4 Blob is
 * POSTed back to the job's webrender upload API.
 */

interface WebRenderConfig {
  script: JobScript;
  schedule: JobTiming[];
  durationInFrames: number;
  format: "landscape" | "vertical";
  jobId: string;
  staticOrigin: string;
}

declare global {
  interface Window {
    __PROMO_WEBRENDER__?: WebRenderConfig;
  }
}

const VERTICAL_WIDTH = 1080;
const VERTICAL_HEIGHT = 1920;

async function render() {
  const cfg = window.__PROMO_WEBRENDER__;
  if (!cfg) {
    throw new Error("webrender: missing window.__PROMO_WEBRENDER__ config");
  }

  const setStage = (stage: string, progress: number) => {
    window.dispatchEvent(
      new CustomEvent("promo-webrender-progress", { detail: { stage, progress } })
    );
  };

  setStage("Checking codec support…", 0);
  const check = await canRenderMediaOnWeb({
    container: "mp4",
    videoCodec: "h264",
    audioCodec: "aac",
    width: cfg.format === "vertical" ? VERTICAL_WIDTH : 1920,
    height: cfg.format === "vertical" ? VERTICAL_HEIGHT : 1080,
  });
  if (!check.canRender) {
    const errors = check.issues
      .filter((i) => i.severity === "error")
      .map((i) => i.message)
      .join("; ");
    throw new Error(
      `This browser cannot render the video locally (${errors || "unknown reason"}). Use Chrome, Edge or another Chromium-based browser.`
    );
  }

  const durationInFrames = Math.max(1, Math.round(cfg.durationInFrames));
  const landscape = cfg.format !== "vertical";

  setStage("Rendering…", 0);
  const result = await renderMediaOnWeb({
    composition: {
      id: landscape
        ? "propertyfinder-promo-job-web"
        : "propertyfinder-promo-job-web-vertical",
      component: JobVideoContent,
      durationInFrames,
      fps: 30,
      width: landscape ? 1920 : VERTICAL_WIDTH,
      height: landscape ? 1080 : VERTICAL_HEIGHT,
      defaultProps: {
        script: cfg.script,
        schedule: cfg.schedule,
        durationInFrames,
      },
    },
    inputProps: {
      script: cfg.script,
      schedule: cfg.schedule,
      durationInFrames,
    },
    container: "mp4",
    videoCodec: "h264",
    audioCodec: "aac",
    videoBitrate: "high",
    audioBitrate: 192_000,
    hardwareAcceleration: "no-preference",
    pageResponsiveness: "medium",
    onProgress: (p) => {
      setStage(
        `Rendering… ${Math.round(p.progress * 100)}%`,
        Math.max(2, Math.round(p.progress * 98))
      );
    },
  });

  setStage("Uploading…", 98);
  const blob = await result.getBlob();
  const form = new FormData();
  form.append("file", blob, "out-web.mp4");
  form.append("format", cfg.format);
  const res = await fetch(
    `${cfg.staticOrigin}/api/admin/promo-video/${cfg.jobId}/webrender`,
    {
      method: "POST",
      body: form,
      credentials: "include",
    }
  );
  if (!res.ok) {
    const text = await res.text().catch(() => "");
    throw new Error(`Upload failed (${res.status}): ${text.slice(0, 200)}`);
  }

  setStage("Done", 100);
  window.dispatchEvent(new CustomEvent("promo-webrender-done", { detail: { ok: true } }));
}

render().catch((err) => {
  console.error("[webrender]", err);
  window.dispatchEvent(
    new CustomEvent("promo-webrender-error", {
      detail: { message: err instanceof Error ? err.message : String(err) },
    })
  );
});
