import "server-only";

import {
  getConversionPresetDefinition,
  getVideoFormatDefinition
} from "@/lib/media-processing/conversion-presets";
import { runFfmpegAndExpectFile } from "@/lib/ffmpeg/ffmpeg";
import { createTempOutputPath } from "@/lib/uploads/temp-files";
import type {
  ConversionQualityPreset,
  FormatConversionResult,
  VideoOutputFormat
} from "@/types/media-processing";

interface ConvertVideoFormatOptions {
  inputPath: string;
  outputFormat: VideoOutputFormat;
  preset: ConversionQualityPreset;
  preserveAudio?: boolean;
  outputPath?: string;
}

export async function convertVideoFormat({
  inputPath,
  outputFormat,
  preset,
  preserveAudio = true,
  outputPath
}: ConvertVideoFormatOptions): Promise<FormatConversionResult> {
  const presetDefinition = getConversionPresetDefinition(preset);
  const formatDefinition = getVideoFormatDefinition(outputFormat);

  const finalOutputPath =
    outputPath ||
    (await createTempOutputPath({
      extension: formatDefinition.extension,
      prefix: "convert"
    }));

  const args = ["-hide_banner", "-loglevel", "error", "-y", "-i", inputPath];

  // Keep original aspect ratio while normalizing odd dimensions for codec compatibility.
  args.push("-vf", "scale=trunc(iw/2)*2:trunc(ih/2)*2");

  switch (outputFormat) {
    case "mp4":
    case "mov":
    case "mkv":
      args.push(
        "-c:v",
        "libx264",
        "-preset",
        "medium",
        "-crf",
        presetDefinition.h264Crf,
        "-pix_fmt",
        "yuv420p"
      );
      if (outputFormat === "mp4" || outputFormat === "mov") {
        args.push("-movflags", "+faststart");
      }
      break;
    case "webm":
      args.push(
        "-c:v",
        "libvpx-vp9",
        "-crf",
        presetDefinition.webmCrf,
        "-b:v",
        "0",
        "-pix_fmt",
        "yuv420p"
      );
      break;
    case "avi":
      args.push("-c:v", "mpeg4", "-q:v", presetDefinition.aviQualityScale);
      break;
    default:
      break;
  }

  if (preserveAudio) {
    if (outputFormat === "webm") {
      args.push("-c:a", "libopus", "-b:a", "160k");
    } else if (outputFormat === "avi") {
      args.push("-c:a", "libmp3lame", "-b:a", "192k");
    } else {
      args.push("-c:a", "aac", "-b:a", "192k");
    }
  } else {
    args.push("-an");
  }

  args.push(finalOutputPath);

  await runFfmpegAndExpectFile(args, finalOutputPath);

  return {
    outputPath: finalOutputPath,
    format: outputFormat,
    preset
  };
}
