import "server-only";

import { runFfmpegAndExpectFile } from "@/lib/ffmpeg/ffmpeg";
import { createTempOutputPath } from "@/lib/uploads/temp-files";
import { validateOptionalTimeRange } from "@/lib/validations/media-file";
import type { AudioExtractionResult, AudioOutputFormat } from "@/types/media-processing";

interface ExtractAudioOptions {
  inputPath: string;
  outputFormat: AudioOutputFormat;
  startSeconds?: number | null;
  endSeconds?: number | null;
  outputPath?: string;
}

export async function extractAudio({
  inputPath,
  outputFormat,
  startSeconds = null,
  endSeconds = null,
  outputPath
}: ExtractAudioOptions): Promise<AudioExtractionResult> {
  validateOptionalTimeRange(startSeconds, endSeconds);

  const finalOutputPath =
    outputPath ||
    (await createTempOutputPath({
      extension: outputFormat,
      prefix: "audio"
    }));

  const args = ["-hide_banner", "-loglevel", "error", "-y", "-i", inputPath];
  const hasRange = startSeconds != null && endSeconds != null;

  if (startSeconds != null) {
    args.push("-ss", startSeconds.toFixed(3));
  }

  if (hasRange) {
    args.push("-t", (endSeconds - startSeconds).toFixed(3));
  } else if (endSeconds != null) {
    args.push("-to", endSeconds.toFixed(3));
  }

  args.push("-vn");

  switch (outputFormat) {
    case "mp3":
      args.push("-c:a", "libmp3lame", "-b:a", "192k");
      break;
    case "wav":
      args.push("-c:a", "pcm_s16le");
      break;
    case "m4a":
      args.push("-c:a", "aac", "-b:a", "192k");
      break;
    default:
      break;
  }

  args.push(finalOutputPath);

  await runFfmpegAndExpectFile(args, finalOutputPath);

  return {
    outputPath: finalOutputPath,
    format: outputFormat,
    startSeconds,
    endSeconds
  };
}
