import { spawn } from "child_process";
import { promises as fs } from "fs";
import path from "path";
import { getVideoConfig } from "@/lib/generation/video-config";
import { getLocalMediaPath, resolveLocalMediaPath } from "@/lib/storage/media-files";
import { isFfmpegAvailable } from "@/lib/generation/ffmpeg-video";
import { resolveBannerLayoutId, type BannerLayoutId } from "@/lib/generation/banner-layouts";

/** Panel geometry matching buildBrandedSocialCardSvg layouts (1080×1080). */
export function resolveHeroPanelBox(
  layoutSeed: number,
  layoutIdOverride?: BannerLayoutId | null,
): {
  x: number;
  y: number;
  width: number;
  height: number;
} {
  const layoutId = layoutIdOverride || resolveBannerLayoutId(layoutSeed);
  if (layoutId === "left_image") {
    return { x: 40, y: 150, width: 480, height: 520 };
  }
  if (layoutId === "center_cta") {
    return { x: 140, y: 680, width: 800, height: 200 };
  }
  if (layoutId === "feature_focused") {
    return { x: 560, y: 180, width: 480, height: 420 };
  }
  if (layoutId === "statistics_focused") {
    return { x: 560, y: 150, width: 480, height: 460 };
  }
  if (layoutId === "full_bleed") {
    return { x: 420, y: 120, width: 620, height: 760 };
  }
  if (layoutId === "top_hero") {
    return { x: 40, y: 40, width: 1000, height: 480 };
  }
  if (layoutId === "bottom_hero") {
    return { x: 40, y: 540, width: 1000, height: 380 };
  }
  if (layoutId === "split_card") {
    return { x: 560, y: 200, width: 460, height: 560 };
  }
  if (layoutId === "timeline") {
    return { x: 40, y: 560, width: 1000, height: 280 };
  }
  if (layoutId === "infographic" || layoutId === "enterprise_dashboard") {
    // No side hero — storytelling is typographic/infographic; tiny footer accent only.
    return { x: 40, y: 900, width: 1000, height: 120 };
  }
  return { x: 560, y: 160, width: 480, height: 500 };
}

/**
 * Overlay a photoreal hero PNG onto a rasterized banner.
 * FFmpeg cannot reliably paint SVG &lt;image href="file://…"&gt; embeds — this is the reliable path.
 */
export async function applyHeroOverlayToImageFile(input: {
  imagePath: string;
  heroPath: string;
  assetId: string;
  layoutSeed: number;
  layoutId?: BannerLayoutId | null;
}): Promise<{ ok: true; path: string } | { ok: false; error: string }> {
  const { imagePath, heroPath, assetId, layoutSeed, layoutId } = input;

  if (imagePath.toLowerCase().endsWith(".svg")) {
    return { ok: false, error: "Hero overlay requires raster PNG, not SVG" };
  }

  try {
    await fs.access(heroPath);
  } catch {
    return { ok: false, error: `Hero file missing: ${heroPath}` };
  }

  const ffmpegOk = await isFfmpegAvailable();
  if (!ffmpegOk) {
    return { ok: false, error: "FFmpeg not available for hero overlay" };
  }

  const box = resolveHeroPanelBox(layoutSeed, layoutId);
  // Skip near-invisible hero strips for infographic/dashboard (keeps composition typographic).
  if (box.height < 160) {
    return { ok: true, path: imagePath };
  }

  const cfg = getVideoConfig();
  const tempOut = getLocalMediaPath(`${path.basename(assetId)}-hero-overlay.png`);

  const filter = [
    `[1:v]scale=${box.width}:${box.height}:force_original_aspect_ratio=increase,`,
    `crop=${box.width}:${box.height},format=rgba[hero];`,
    `[0:v][hero]overlay=${box.x}:${box.y}`,
  ].join("");

  const overlayResult = await new Promise<{ ok: true } | { ok: false; error: string }>((resolve) => {
    const args = ["-y", "-i", imagePath, "-i", heroPath, "-filter_complex", filter, tempOut];
    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: err.message }));
    proc.on("close", (code) => {
      if (code === 0) resolve({ ok: true });
      else resolve({ ok: false, error: stderr.slice(-400) || `FFmpeg exited ${code}` });
    });
  });

  if (!overlayResult.ok) {
    await fs.unlink(tempOut).catch(() => undefined);
    return overlayResult;
  }

  await fs.copyFile(tempOut, imagePath);
  await fs.unlink(tempOut).catch(() => undefined);
  return { ok: true, path: imagePath };
}

export async function applyHeroOverlayToPersistedImage(input: {
  imageApiUrl: string | null;
  heroFilePath: string | null | undefined;
  assetId: string;
  layoutSeed: number;
  layoutId?: BannerLayoutId | null;
}): Promise<string | null> {
  if (!input.imageApiUrl || !input.heroFilePath) return input.imageApiUrl;

  const imagePath = resolveLocalMediaPath(input.imageApiUrl);
  if (!imagePath) return input.imageApiUrl;

  const result = await applyHeroOverlayToImageFile({
    imagePath,
    heroPath: input.heroFilePath,
    assetId: input.assetId,
    layoutSeed: input.layoutSeed,
    layoutId: input.layoutId,
  });

  if (!result.ok) {
    console.warn("[PostSync] Hero overlay failed:", result.error);
  }
  return input.imageApiUrl;
}
