const fs = require("fs");
const path = require("path");

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

function isImageFile(filePath) {
  return IMAGE_EXT.has(path.extname(filePath).toLowerCase());
}

function listMediaFiles(folderPath) {
  if (!folderPath || !fs.existsSync(folderPath)) return [];
  const entries = fs.readdirSync(folderPath, { withFileTypes: true });
  const files = [];
  for (const entry of entries) {
    if (!entry.isFile()) continue;
    const ext = path.extname(entry.name).toLowerCase();
    if (
      [".mp4", ".mov", ".webm", ".mkv", ".m4v", ".avi", ...IMAGE_EXT].includes(ext)
    ) {
      files.push(path.join(folderPath, entry.name));
    }
  }
  return files.sort();
}

function pickFromFolder(selectionMode, folderPath, specifiedPath) {
  if (selectionMode === "specified" && specifiedPath) {
    return specifiedPath;
  }
  const files = listMediaFiles(folderPath);
  if (!files.length) return null;
  if (selectionMode === "sequential") {
    return files[0];
  }
  return files[Math.floor(Math.random() * files.length)];
}

function buildSubtitleModeReplacements(records, subtitleModeConfig, probeVideoDuration) {
  const mappings = Array.isArray(subtitleModeConfig?.mappings)
    ? subtitleModeConfig.mappings
    : [];
  const replacements = [];

  for (const mapping of mappings) {
    if (!mapping?.materialPath || !fs.existsSync(mapping.materialPath)) continue;
    const indices = Array.isArray(mapping.subtitleIndices)
      ? mapping.subtitleIndices
      : [];
    if (!indices.length || !records.length) continue;

    let minStart = Infinity;
    let maxEnd = -Infinity;
    for (const idx of indices) {
      const record = records[idx];
      if (!record) continue;
      const startSec = Number(record.start ?? record.startTime ?? 0) / 1000;
      const endSec = Number(record.end ?? record.endTime ?? 0) / 1000;
      minStart = Math.min(minStart, startSec);
      maxEnd = Math.max(maxEnd, endSec);
    }
    if (!Number.isFinite(minStart) || !Number.isFinite(maxEnd)) continue;
    const duration = maxEnd - minStart;
    if (duration <= 0) continue;

    const isImage = mapping.isImage ?? isImageFile(mapping.materialPath);
    const materialDuration = isImage
      ? duration
      : probeVideoDuration(mapping.materialPath);

    replacements.push({
      startTime: minStart,
      duration,
      materialPath: mapping.materialPath,
      materialDuration,
      materialStartOffset: 0,
      displayMode: mapping.displayMode || "fullscreen",
      pipPosition: mapping.pipPosition || "bottom-right",
      pipSizePercent: mapping.pipSizePercent ?? 30,
      pipScaleMode: mapping.pipScaleMode || "fit",
      isImage,
      originalVideoMinimized: mapping.originalVideoMinimized,
    });
  }

  return replacements.sort((a, b) => a.startTime - b.startTime);
}

function buildFixedModeReplacements(fixedModeConfig, videoDuration, probeVideoDuration) {
  const replacements = [];
  if (!fixedModeConfig?.enabled) return replacements;

  const segments = [
    { key: "opening", reason: "片头" },
    { key: "middle", reason: "片中" },
    { key: "ending", reason: "片尾" },
  ];

  for (const { key, reason } of segments) {
    const seg = fixedModeConfig[key];
    if (!seg?.enabled) continue;

    const min = Number(seg.timeRange?.durationMin ?? 2);
    const max = Number(seg.timeRange?.durationMax ?? 5);
    let startTime = 0;
    let duration = max - min;
    if (key === "middle") {
      const mid = videoDuration / 2;
      startTime = Math.max(0, mid + min);
      duration = Math.min(videoDuration, mid + max) - startTime;
    } else if (key === "ending") {
      duration = max - min;
      startTime = Math.max(0, videoDuration - duration);
    } else {
      startTime = min;
      duration = max - min;
    }
    if (duration <= 0 || startTime >= videoDuration) continue;

    const materialPath = pickFromFolder(
      seg.selectionMode || "random",
      seg.materialFolderPath,
      seg.specifiedMaterialPath,
    );
    if (!materialPath || !fs.existsSync(materialPath)) continue;

    const isImage = isImageFile(materialPath);
    replacements.push({
      startTime,
      duration,
      materialPath,
      materialDuration: isImage ? duration : probeVideoDuration(materialPath),
      materialStartOffset: 0,
      displayMode: seg.displayMode || "fullscreen",
      pipPosition: seg.pipPosition || "bottom-right",
      pipSizePercent: seg.pipSizePercent ?? 30,
      pipScaleMode: seg.pipScaleMode || "fit",
      isImage,
      originalVideoMinimized: seg.originalVideoMinimized,
      reason,
    });
  }

  return replacements.sort((a, b) => a.startTime - b.startTime);
}

function buildReplacementsFromMixCutSettings(settings, videoDuration, probeVideoDuration) {
  if (!settings || typeof settings !== "object" || !settings.enabled) {
    return [];
  }

  const mode = settings.mode || "subtitle";
  let replacements = [];

  if (mode === "subtitle") {
    const records = Array.isArray(settings.records) ? settings.records : [];
    replacements = buildSubtitleModeReplacements(
      records,
      settings.subtitleModeConfig,
      probeVideoDuration,
    );
  } else if (mode === "fixed" && settings.fixedModeConfig?.enabled) {
    replacements = buildFixedModeReplacements(
      settings.fixedModeConfig,
      videoDuration,
      probeVideoDuration,
    );
  }

  return replacements;
}

module.exports = {
  buildReplacementsFromMixCutSettings,
  buildSubtitleModeReplacements,
  buildFixedModeReplacements,
};
