"use strict";

/**
 * 视频封面生成：优先高级 Python → PIL Python → ffmpeg drawtext 回退
 */
const fs = require("fs");
const path = require("path");
const os = require("os");
const { spawnSync } = require("child_process");

const pipelineNative = require("./pipeline_native.js");
const coverPython = require("./cover_python_runner.js");

const OUTPUT_DIR = path.join(os.tmpdir(), "aiclient-cover");

function ensureDir() {
  fs.mkdirSync(OUTPUT_DIR, { recursive: true });
  return OUTPUT_DIR;
}

function execFfmpeg(args) {
  const ffmpeg = pipelineNative.locateFfmpeg();
  if (!ffmpeg) {
    throw new Error("未找到 ffmpeg，请配置 AICLIENT_FFMPEG_PATH 或 src-tauri/binaries/ffmpeg.exe");
  }
  const r = spawnSync(ffmpeg, args, { encoding: "utf8", windowsHide: true });
  if (r.status !== 0) {
    throw new Error((r.stderr || r.stdout || "").trim() || `ffmpeg 退出码 ${r.status}`);
  }
}

function escapeDrawtext(text) {
  return String(text)
    .replace(/\\/g, "\\\\")
    .replace(/'/g, "'\\''")
    .replace(/:/g, "\\:")
    .replace(/%/g, "\\%");
}

/** ffmpeg drawtext 路径转义（Windows 盘符冒号） */
function escapeFfmpegPath(filePath) {
  return String(filePath).replace(/\\/g, "/").replace(/:/g, "\\:");
}

/**
 * 定位系统中文字体（ffmpeg drawtext 必须指定 fontfile）
 */
function locateCjkFontFile() {
  const scriptsDir = process.env.AICLIENT_COVER_SCRIPTS_DIR || "";
  const windir = process.env.WINDIR || "C:\\Windows";
  const candidates = [
    path.join(scriptsDir, "fonts", "simhei.ttf"),
    path.join(scriptsDir, "fonts", "msyh.ttc"),
    path.join(windir, "Fonts", "simhei.ttf"),
    path.join(windir, "Fonts", "msyh.ttc"),
    path.join(windir, "Fonts", "simsun.ttc"),
    "C:/Windows/Fonts/simhei.ttf",
    "C:/Windows/Fonts/msyh.ttc",
  ];
  for (const p of candidates) {
    if (p && fs.existsSync(p)) return p;
  }
  return null;
}

function buildTextPosition(titlePosition) {
  if (titlePosition === "top") return "y=50";
  if (titlePosition === "center") return "y=(h-text_h)/2";
  return "y=h-text_h-50";
}

const IMAGE_EXT = new Set([".jpg", ".jpeg", ".png", ".bmp", ".webp"]);

function isImagePath(filePath) {
  return IMAGE_EXT.has(path.extname(String(filePath || "")).toLowerCase());
}

function prepareFrameFromSource(sourcePath, tempFramePath, emit) {
  if (isImagePath(sourcePath)) {
    emit?.("正在加载图片素材…");
    execFfmpeg([
      "-i",
      sourcePath,
      "-vf",
      "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:color=black",
      "-y",
      tempFramePath,
    ]);
    return;
  }
  emit?.("正在提取视频帧…");
  execFfmpeg([
    "-ss",
    "00:00:03",
    "-i",
    sourcePath,
    "-vframes",
    "1",
    "-pix_fmt",
    "yuvj420p",
    "-c:v",
    "mjpeg",
    "-strict:v",
    "unofficial",
    "-f",
    "image2",
    "-y",
    tempFramePath,
  ]);
}

function runFfmpegCover({ sourceVideo, titleText, effectStyle, coverPath, tempFramePath, emit }) {
  prepareFrameFromSource(sourceVideo, tempFramePath, emit);

  const titleFontSize = effectStyle.titleFontSize ?? 90;
  const titleFontColor = effectStyle.titleFontColor || "#FFFFFF";
  const titlePosition = effectStyle.titlePosition || "bottom";
  const textPos = buildTextPosition(titlePosition);

  const fontFile = locateCjkFontFile();
  if (!fontFile) {
    throw new Error("未找到中文字体文件，无法使用 ffmpeg 绘制标题（请确认 C:\\Windows\\Fonts\\simhei.ttf 存在）");
  }

  const titleFilePath = path.join(
    OUTPUT_DIR,
    `cover_title_${Date.now()}.txt`,
  );
  fs.writeFileSync(titleFilePath, String(titleText), { encoding: "utf8" });

  const fontOpt = `fontfile='${escapeFfmpegPath(fontFile)}'`;
  const textOpt = `textfile='${escapeFfmpegPath(titleFilePath)}'`;
  const vf = `drawtext=${fontOpt}:${textOpt}:fontsize=${titleFontSize}:fontcolor=${titleFontColor}:x=(w-text_w)/2:${textPos}:shadowcolor=black:shadowx=2:shadowy=2`;

  emit?.("正在叠加标题文字（ffmpeg）…");
  try {
    execFfmpeg(["-i", tempFramePath, "-vf", vf, "-y", coverPath]);
  } finally {
    try {
      fs.unlinkSync(titleFilePath);
    } catch {
      /* ignore */
    }
  }
}

function shouldUsePilCover(effectStyle) {
  if (coverPython.isAdvancedCoverConfig(effectStyle)) return false;
  return (
    (effectStyle.titleStrokeWidth && effectStyle.titleStrokeWidth > 0) ||
    Boolean(effectStyle.titleFontFamily) ||
    Boolean(effectStyle.titleColor) ||
    effectStyle.titleShadowBlur > 0
  );
}

globalThis.__nodejsMain = async function main(params) {
  const p = params || {};
  const videoPath = String(p.videoPath || "").trim();
  const titleText = String(p.titleText || "").trim();
  const effectStyle = p.effectStyle || {};

  if (!videoPath || !fs.existsSync(videoPath)) {
    return { success: false, error: "视频文件不存在，请先在步骤 02/03/05 生成视频" };
  }
  if (!titleText) {
    return { success: false, error: "标题文本不能为空，请先在步骤 04 生成标题" };
  }

  ensureDir();
  const ts = Date.now();
  const tempFramePath = path.join(OUTPUT_DIR, `temp_frame_${ts}.jpg`);
  const coverPath = path.join(OUTPUT_DIR, `cover_${ts}.jpg`);

  let sourceVideo = videoPath;
  const custom = String(effectStyle.customVideoPath || "").trim();
  if (custom && fs.existsSync(custom)) {
    sourceVideo = custom;
  }

  const emit = (status) => globalThis.__native?.emitProgress?.(status);

  try {
    if (coverPython.isAdvancedCoverConfig(effectStyle)) {
      const adv = coverPython.runAdvancedCoverGenerator({
        videoPath: sourceVideo,
        titleText,
        outputPath: coverPath,
        config: effectStyle,
        onProgress: emit,
      });
      if (adv.success) {
        return {
          success: true,
          coverPath: adv.coverPath,
          previewImages: adv.previewImages,
          message: adv.message || "高级封面生成完成",
          mode: "advanced_python",
        };
      }
      emit(`高级生成失败，尝试回退：${(adv.error || "").slice(0, 80)}`);
    } else if (shouldUsePilCover(effectStyle) && coverPython.locatePython()) {
      const pil = coverPython.runBasicCoverGenerator({
        videoPath: sourceVideo,
        titleText,
        outputPath: coverPath,
        config: effectStyle,
        timestamp: 3,
        onProgress: emit,
      });
      if (pil.success) {
        return {
          success: true,
          coverPath: pil.coverPath,
          message: pil.message || "封面生成完成",
          mode: "pil_python",
        };
      }
      emit(`PIL 生成失败，尝试 ffmpeg 回退…`);
    }

    runFfmpegCover({
      sourceVideo,
      titleText,
      effectStyle,
      coverPath,
      tempFramePath,
      emit,
    });

    if (fs.existsSync(tempFramePath)) {
      try {
        fs.unlinkSync(tempFramePath);
      } catch {
        /* ignore */
      }
    }

    if (!fs.existsSync(coverPath)) {
      return { success: false, error: "封面文件未生成" };
    }

    return {
      success: true,
      coverPath,
      message: "封面生成完成",
      mode: "ffmpeg",
    };
  } catch (e) {
    return {
      success: false,
      error: e.message || String(e),
    };
  }
};
