// fallow-ignore-file code-duplication
import { execSync } from "node:child_process";
import { existsSync } from "node:fs";
import { resolve } from "node:path";
import { detectLinuxDistro, ffmpegInstallCommand } from "./linuxDeps.js";

export const FFMPEG_PATH_ENV = "HYPERFRAMES_FFMPEG_PATH";
export const FFPROBE_PATH_ENV = "HYPERFRAMES_FFPROBE_PATH";

function findOnPath(name: "ffmpeg" | "ffprobe"): string | undefined {
  try {
    const cmd = process.platform === "win32" ? `where ${name}` : `which ${name}`;
    const output = execSync(cmd, {
      encoding: "utf-8",
      stdio: ["pipe", "pipe", "pipe"],
      timeout: 5000,
    });
    const first = output
      .split(/\r?\n/)
      .map((s) => s.trim())
      .find(Boolean);
    return first ? resolve(first) : undefined;
  } catch {
    return undefined;
  }
}

// GUI/Dock/launchd-spawned processes on macOS don't inherit the shell PATH, so
// `which ffmpeg` fails even when ffmpeg is installed via Homebrew. Probe the
// well-known install dirs as a fallback. (No-op on Windows, where `where` and
// installer-added PATH entries cover it.)
const COMMON_BIN_DIRS =
  process.platform === "win32"
    ? []
    : ["/opt/homebrew/bin", "/usr/local/bin", "/usr/bin", "/bin", "/snap/bin"];

function findInCommonDirs(name: "ffmpeg" | "ffprobe"): string | undefined {
  for (const dir of COMMON_BIN_DIRS) {
    const candidate = `${dir}/${name}`;
    if (existsSync(candidate)) return candidate;
  }
  return undefined;
}

function findConfiguredBinary(
  envName: string,
  binaryName: "ffmpeg" | "ffprobe",
): string | undefined {
  const configured = process.env[envName]?.trim();
  if (configured) return existsSync(configured) ? resolve(configured) : undefined;
  return findOnPath(binaryName) ?? findInCommonDirs(binaryName);
}

export function findFFmpeg(): string | undefined {
  return findConfiguredBinary(FFMPEG_PATH_ENV, "ffmpeg");
}

export function findFFprobe(): string | undefined {
  return findConfiguredBinary(FFPROBE_PATH_ENV, "ffprobe");
}

export function getFFmpegInstallHint(): string {
  switch (process.platform) {
    case "darwin":
      return "brew install ffmpeg";
    case "linux": {
      // Distro-aware so WSL/Fedora/Arch/Alpine users get a command that
      // actually works instead of a Debian-only `apt` line.
      const distro = detectLinuxDistro();
      return ffmpegInstallCommand(distro.family);
    }
    case "win32":
      return "Download the 64-bit Windows build from https://ffmpeg.org/download.html#build-windows and add its bin/ directory to PATH.";
    default:
      return "https://ffmpeg.org/download.html";
  }
}
