import { execSync } from "node:child_process";

function run(cmd) {
  try {
    return execSync(cmd, { stdio: "pipe" }).toString().trim();
  } catch {
    return null;
  }
}

function parseMajorMinor(v) {
  if (!v) return [0, 0];
  const m = v.match(/(\d+)\.(\d+)/);
  return m ? [parseInt(m[1], 10), parseInt(m[2], 10)] : [0, 0];
}

const PREREQ_DEFS = [
  {
    name: "macOS",
    checkFn() {
      const installed = run("uname -s") === "Darwin";
      return { installed, version: installed ? (run("sw_vers -productVersion") ?? undefined) : undefined };
    },
    installCommand: null,
  },
  {
    name: "Homebrew",
    checkFn() {
      if (!run("which brew")) return { installed: false };
      const out = run("brew --version");
      return { installed: true, version: out?.split("\n")[0].replace("Homebrew ", "") };
    },
    installCommand: '/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
  },
  {
    name: "Node.js",
    checkFn() {
      if (!run("which node")) return { installed: false };
      const v = run("node --version")?.replace("v", "");
      const [major] = parseMajorMinor(v);
      return { installed: major >= 22, version: v };
    },
    installCommand: "brew install node@22 && brew link --overwrite node@22",
  },
  {
    name: "Python 3.12+",
    checkFn() {
      // brew installs python3.12 as a keg-only binary, not as python3, on macOS
      if (run("which python3.12")) {
        const v = run("python3.12 --version")?.replace("Python ", "");
        const [major, minor] = parseMajorMinor(v);
        if (major === 3 && minor >= 12) return { installed: true, version: v };
      }
      if (!run("which python3")) return { installed: false };
      const v = run("python3 --version")?.replace("Python ", "");
      const [major, minor] = parseMajorMinor(v);
      return { installed: major === 3 && minor >= 12, version: v };
    },
    installCommand: "brew install python@3.12",
  },
  {
    name: "PM2",
    checkFn() {
      if (!run("which pm2")) return { installed: false };
      return { installed: true, version: run("pm2 --version") ?? undefined };
    },
    installCommand: "npm install -g pm2",
  },
  {
    name: "Claude Code CLI",
    checkFn() {
      if (!run("which claude")) return { installed: false };
      return { installed: true, version: run("claude --version") ?? undefined };
    },
    installCommand: "curl -fsSL https://claude.ai/install.sh | bash",
  },
  {
    name: "SQLite3",
    checkFn() {
      if (!run("which sqlite3")) return { installed: false };
      const v = run("sqlite3 --version")?.split(" ")[0];
      return { installed: true, version: v };
    },
    installCommand: "brew install sqlite3",
  },
  {
    name: "Git",
    checkFn() {
      if (!run("which git")) return { installed: false };
      const v = run("git --version")?.replace("git version ", "");
      return { installed: true, version: v };
    },
    installCommand: "brew install git",
  },
];

export async function checkPrereqs() {
  return PREREQ_DEFS.map(({ name, checkFn, installCommand }) => {
    const { installed, version } = checkFn();
    return { name, installed, version, installCommand };
  });
}

export async function installPrereq(name) {
  const def = PREREQ_DEFS.find(d => d.name === name);
  if (!def) throw new Error(`Unknown prerequisite: ${name}`);
  if (!def.installCommand) throw new Error(`No install command available for: ${name}`);
  console.log(`Installing ${name}...`);
  execSync(def.installCommand, { stdio: "inherit", shell: true });
  console.log(`${name} installed.`);
}
