import { spawn } from "child_process";
import { promises as fs } from "fs";
import { getVideoConfig } from "./video-config";

export async function isFfmpegAvailable(): Promise<boolean> {
  const cfg = getVideoConfig();
  return new Promise((resolve) => {
    const proc = spawn(cfg.ffmpegPath, ["-version"], { stdio: "ignore" });
    proc.on("error", () => resolve(false));
    proc.on("close", (code) => resolve(code === 0));
  });
}

/**
 * Build a vertical 9:16 MP4 from multiple still slides (5-screen story video).
 */
export async function buildMultiSlideMp4(input: {
  slidePaths: string[];
  outputPath: string;
  durationSeconds?: number;
}): Promise<{ ok: true } | { ok: false; error: string }> {
  const cfg = getVideoConfig();
  const slides = input.slidePaths.filter(Boolean);
  if (slides.length === 0) {
    return { ok: false, error: "No slide images provided" };
  }

  const totalDuration = input.durationSeconds ?? cfg.durationSeconds;
  const slideDuration = Math.max(2, totalDuration / slides.length);
  const fps = 25;

  for (const slidePath of slides) {
    try {
      await fs.access(slidePath);
    } catch {
      return { ok: false, error: `Slide not found: ${slidePath}` };
    }
  }

  const scaleCrop = `scale=${cfg.width}:${cfg.height}:force_original_aspect_ratio=increase,crop=${cfg.width}:${cfg.height}`;

  const filterParts: string[] = [];
  for (let i = 0; i < slides.length; i++) {
    filterParts.push(
      `[${i}:v]${scaleCrop},fps=${fps},format=yuv420p,setpts=PTS-STARTPTS,trim=duration=${slideDuration.toFixed(2)}[v${i}]`,
    );
  }
  const concatInputs = slides.map((_, i) => `[v${i}]`).join("");
  filterParts.push(`${concatInputs}concat=n=${slides.length}:v=1:a=0[outv]`);

  return new Promise((resolve) => {
    const args = ["-y"];
    for (const slidePath of slides) {
      args.push("-loop", "1", "-t", String(slideDuration), "-i", slidePath);
    }
    args.push(
      "-filter_complex",
      filterParts.join(";"),
      "-map",
      "[outv]",
      "-c:v",
      "libx264",
      "-pix_fmt",
      "yuv420p",
      "-t",
      String(slideDuration * slides.length),
      input.outputPath,
    );

    const proc = spawn(cfg.ffmpegPath, args, { stdio: ["ignore", "pipe", "pipe"] });
    let stderr = "";

    proc.stderr.on("data", (chunk: Buffer) => {
      stderr += chunk.toString();
    });

    proc.on("error", (err) => {
      resolve({
        ok: false,
        error: `FFmpeg not found (${cfg.ffmpegPath}). ${err.message}`,
      });
    });

    proc.on("close", (code) => {
      if (code === 0) resolve({ ok: true });
      else resolve({ ok: false, error: `FFmpeg exited ${code}: ${stderr.slice(-500)}` });
    });
  });
}

/**
 * Build a vertical 9:16 MP4 slideshow from a still image (Ken Burns zoom).
 * Requires FFmpeg on the server PATH or FFMPEG_PATH in .env.local.
 */
export async function buildSlideshowMp4(input: {
  imagePath: string;
  outputPath: string;
  durationSeconds?: number;
}): Promise<{ ok: true } | { ok: false; error: string }> {
  const cfg = getVideoConfig();
  const duration = input.durationSeconds ?? cfg.durationSeconds;
  const fps = 25;
  const frames = duration * fps;

  try {
    await fs.access(input.imagePath);
  } catch {
    return { ok: false, error: `Image not found: ${input.imagePath}` };
  }

  const vf = [
    `scale=${cfg.width}:${cfg.height}:force_original_aspect_ratio=increase`,
    `crop=${cfg.width}:${cfg.height}`,
    `zoompan=z='min(zoom+0.0004,1.15)':d=${frames}:x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':s=${cfg.width}x${cfg.height}:fps=${fps}`,
  ].join(",");

  return new Promise((resolve) => {
    const args = [
      "-y",
      "-loop",
      "1",
      "-i",
      input.imagePath,
      "-vf",
      vf,
      "-c:v",
      "libx264",
      "-pix_fmt",
      "yuv420p",
      "-t",
      String(duration),
      input.outputPath,
    ];

    const proc = spawn(cfg.ffmpegPath, args, { stdio: ["ignore", "pipe", "pipe"] });
    let stderr = "";

    proc.stderr.on("data", (chunk: Buffer) => {
      stderr += chunk.toString();
    });

    proc.on("error", (err) => {
      resolve({
        ok: false,
        error: `FFmpeg not found (${cfg.ffmpegPath}). Install FFmpeg or set FFMPEG_PATH. ${err.message}`,
      });
    });

    proc.on("close", (code) => {
      if (code === 0) {
        resolve({ ok: true });
      } else {
        resolve({
          ok: false,
          error: `FFmpeg exited ${code}: ${stderr.slice(-400)}`,
        });
      }
    });
  });
}
