#!/usr/bin/env node
// preinstall hook — runs BEFORE npm installs dependencies.
// Pure CJS (no ESM, no backticks) so it works on any Node version.
// Cross-platform: Linux, macOS, Windows (cmd, PowerShell, Git Bash).
// If Node is too old, guides the user through installing Node 22.
var nodeVersion = parseInt(process.versions.node, 10);

if (nodeVersion >= 22) {
  // Good to go — let npm continue installing deps normally
  process.exit(0);
}

// Prevent infinite loop: if we're inside a self-triggered reinstall, bail
if (process.env.OA_SELF_UPGRADE === "1") {
  console.log("  [preinstall] Skipping — already inside a self-upgrade.");
  console.log("  If this Node is still too old, open a new terminal with Node 22 and run:");
  console.log("    npm i -g open-agents-ai");
  process.exit(1);
}

var os = require("os");
var path = require("path");
var fs = require("fs");
var childProcess = require("child_process");
var readline = require("readline");
var https = require("https");
var http = require("http");

var platform = os.platform();  // "win32", "linux", "darwin"
var arch = os.arch();
var isWindows = platform === "win32";

console.log("");
console.log("  +---------------------------------------------------+");
console.log("  |           open-agents -- Node.js Check             |");
console.log("  +---------------------------------------------------+");
console.log("");
console.log("  Your Node.js:  " + process.version);
console.log("  Required:      >= 22.0.0");
console.log("  Platform:      " + platform + "/" + arch);
console.log("");

// ── Cross-platform helpers ───────────────────────────────────────────────

function hasCmd(cmd) {
  try {
    if (isWindows) {
      childProcess.execSync("where " + cmd, { stdio: "pipe", timeout: 5000 });
    } else {
      childProcess.execSync("which " + cmd, { stdio: "pipe", timeout: 3000 });
    }
    return true;
  } catch (e) {
    return false;
  }
}

function run(cmd, opts) {
  console.log("  $ " + cmd);
  try {
    childProcess.execSync(cmd, Object.assign({ stdio: "inherit" }, opts || {}));
    return true;
  } catch (e) {
    return false;
  }
}

var rl = readline.createInterface({ input: process.stdin, output: process.stdout });

function ask(question, cb) {
  rl.question(question, function(answer) {
    cb(answer.trim().toLowerCase());
  });
}

function bail(msg) {
  console.log(msg);
  rl.close();
  process.exit(1);
}

// ── Node.js-native HTTPS downloader (works everywhere, no curl needed) ──

function download(url, cb) {
  var mod = url.indexOf("https:") === 0 ? https : http;
  mod.get(url, function(res) {
    // Follow redirects (301/302/307/308)
    if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
      download(res.headers.location, cb);
      return;
    }
    if (res.statusCode !== 200) {
      cb(new Error("HTTP " + res.statusCode + " from " + url), null);
      return;
    }
    var chunks = [];
    res.on("data", function(chunk) { chunks.push(chunk); });
    res.on("end", function() { cb(null, Buffer.concat(chunks)); });
    res.on("error", function(err) { cb(err, null); });
  }).on("error", function(err) { cb(err, null); });
}

function downloadToFile(url, dest, cb) {
  download(url, function(err, data) {
    if (err) { cb(err); return; }
    try {
      fs.writeFileSync(dest, data);
      cb(null);
    } catch (e) {
      cb(e);
    }
  });
}

// ── Shell / downloader detection ─────────────────────────────────────────

// Returns a shell command prefix for piped downloads, or null.
// On Windows, we prefer the Node.js-native download() function instead.
function getShellDownloader() {
  if (hasCmd("curl")) return "curl -fsSL";
  if (hasCmd("wget")) return "wget -qO-";
  return null;
}

function getShell() {
  if (isWindows) return null; // Windows doesn't use bash shells for nvm
  return process.env.SHELL || "/bin/bash";
}

// ── nvm detection (Unix) ─────────────────────────────────────────────────

var nvmDir = process.env.NVM_DIR || path.join(os.homedir(), ".nvm");
var hasNvm = false;
try { fs.statSync(path.join(nvmDir, "nvm.sh")); hasNvm = true; } catch (e) {}

// nvm-windows detection
var nvmWinDir = process.env.NVM_HOME || "";
var hasNvmWin = false;
if (isWindows) {
  if (!nvmWinDir) {
    // Common install location
    var appData = process.env.APPDATA || path.join(os.homedir(), "AppData", "Roaming");
    nvmWinDir = path.join(appData, "nvm");
  }
  try { fs.statSync(path.join(nvmWinDir, "nvm.exe")); hasNvmWin = true; } catch (e) {}
  if (!hasNvmWin) { try { hasNvmWin = hasCmd("nvm"); } catch (e) {} }
}

// ── Windows flow ─────────────────────────────────────────────────────────

function windowsInstallNode(next) {
  console.log("  Windows detected. Checking Node.js install options...");
  console.log("");

  // Option 1: nvm-windows is installed
  if (hasNvmWin) {
    console.log("  nvm-windows found.");
    ask("  Install Node.js 22 via nvm? [Y/n] ", function(a) {
      if (a === "n" || a === "no") {
        bail("\n  Install manually:\n    nvm install 22\n    nvm use 22\n    npm i -g open-agents-ai\n");
        return;
      }
      var ok = run("nvm install 22") && run("nvm use 22");
      if (!ok) {
        bail("\n  nvm install failed. Try manually:\n    nvm install 22\n    nvm use 22\n    npm i -g open-agents-ai\n");
        return;
      }
      next();
    });
    return;
  }

  // Option 2: winget available (Windows 10 1709+ / Windows 11)
  if (hasCmd("winget")) {
    ask("  Install Node.js 22 via winget? [Y/n] ", function(a) {
      if (a === "n" || a === "no") {
        windowsFallbackInstructions();
        return;
      }
      var ok = run("winget install -e --id OpenJS.NodeJS.LTS --accept-source-agreements --accept-package-agreements");
      if (ok) {
        console.log("");
        console.log("  Node.js 22 installed via winget.");
        console.log("  Please close and reopen your terminal, then run:");
        console.log("    npm i -g open-agents-ai");
        console.log("");
        rl.close();
        process.exit(0);
        return;
      }
      console.log("  winget install failed, trying alternative...");
      windowsDirectDownload(next);
    });
    return;
  }

  // Option 3: choco available
  if (hasCmd("choco")) {
    ask("  Install Node.js 22 via Chocolatey? [Y/n] ", function(a) {
      if (a === "n" || a === "no") {
        windowsFallbackInstructions();
        return;
      }
      var ok = run("choco install nodejs-lts -y");
      if (ok) {
        console.log("");
        console.log("  Node.js installed via Chocolatey.");
        console.log("  Please close and reopen your terminal, then run:");
        console.log("    npm i -g open-agents-ai");
        console.log("");
        rl.close();
        process.exit(0);
        return;
      }
      console.log("  choco install failed, trying alternative...");
      windowsDirectDownload(next);
    });
    return;
  }

  // Option 4: scoop available
  if (hasCmd("scoop")) {
    ask("  Install Node.js 22 via scoop? [Y/n] ", function(a) {
      if (a === "n" || a === "no") {
        windowsFallbackInstructions();
        return;
      }
      var ok = run("scoop install nodejs-lts");
      if (ok) {
        console.log("");
        console.log("  Node.js installed via scoop.");
        console.log("  Please close and reopen your terminal, then run:");
        console.log("    npm i -g open-agents-ai");
        console.log("");
        rl.close();
        process.exit(0);
        return;
      }
      console.log("  scoop install failed, trying direct download...");
      windowsDirectDownload(next);
    });
    return;
  }

  // Option 5: direct MSI download via Node.js native https
  windowsDirectDownload(next);
}

function windowsDirectDownload(next) {
  var msiArch = arch === "x64" ? "x64" : arch === "arm64" ? "arm64" : "x86";
  var msiUrl = "https://nodejs.org/dist/v22.16.0/node-v22.16.0-" + msiArch + ".msi";
  var msiDest = path.join(os.tmpdir(), "node-v22-installer.msi");

  ask("  Download Node.js 22 installer directly? [Y/n] ", function(a) {
    if (a === "n" || a === "no") {
      windowsFallbackInstructions();
      return;
    }
    console.log("");
    console.log("  Downloading Node.js 22 from nodejs.org...");
    console.log("  URL: " + msiUrl);
    console.log("  (this may take a moment)");
    console.log("");

    downloadToFile(msiUrl, msiDest, function(err) {
      if (err) {
        console.log("  Download failed: " + (err.message || err));
        console.log("");
        windowsFallbackInstructions();
        return;
      }
      console.log("  Downloaded to: " + msiDest);
      console.log("");
      console.log("  Launching installer...");
      var ok = run("msiexec /i \"" + msiDest + "\"");
      if (ok) {
        console.log("");
        console.log("  Node.js 22 installer completed.");
        console.log("  Close and reopen your terminal, then run:");
        console.log("    npm i -g open-agents-ai");
        console.log("");
      } else {
        console.log("");
        console.log("  Installer may have been cancelled or requires admin privileges.");
        console.log("  Run the installer manually:");
        console.log("    " + msiDest);
        console.log("");
        console.log("  Then reopen your terminal and run:");
        console.log("    npm i -g open-agents-ai");
        console.log("");
      }
      rl.close();
      process.exit(0);
    });
  });
}

function windowsFallbackInstructions() {
  bail(
    "\n  Install Node.js 22 manually:\n\n" +
    "  Option 1 — Download from nodejs.org:\n" +
    "    https://nodejs.org/en/download/\n\n" +
    "  Option 2 — winget (Windows 10/11):\n" +
    "    winget install OpenJS.NodeJS.LTS\n\n" +
    "  Option 3 — Chocolatey:\n" +
    "    choco install nodejs-lts\n\n" +
    "  Option 4 — nvm-windows:\n" +
    "    https://github.com/coreybutler/nvm-windows/releases\n" +
    "    nvm install 22 && nvm use 22\n\n" +
    "  Then re-run:  npm i -g open-agents-ai\n"
  );
}

// ── Unix flow (Linux / macOS) ────────────────────────────────────────────

function unixInstallNvm(next) {
  if (hasNvm) {
    console.log("  nvm found at " + nvmDir);
    console.log("");
    next();
    return;
  }

  ask("  nvm is not installed. Install nvm now? [Y/n] ", function(a) {
    if (a === "n" || a === "no") {
      bail(
        "\n  Install nvm manually:\n" +
        "    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash\n" +
        "    source ~/.bashrc\n" +
        "    nvm install 22\n" +
        "    npm i -g open-agents-ai\n"
      );
      return;
    }
    console.log("");

    // Try shell downloader first (curl/wget), fall back to Node.js native https
    var dl = getShellDownloader();
    if (dl) {
      var ok = run(dl + " https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash");
      if (ok) {
        nvmDir = process.env.NVM_DIR || path.join(os.homedir(), ".nvm");
        hasNvm = true;
        console.log("");
        next();
        return;
      }
    }

    // Fallback: download nvm install script via Node.js https module
    console.log("  Downloading nvm install script via Node.js...");
    download("https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh", function(err, data) {
      if (err) {
        bail("\n  Could not download nvm install script: " + (err.message || err) +
          "\n  Install nvm manually: https://github.com/nvm-sh/nvm#installing-and-updating\n");
        return;
      }
      var scriptPath = path.join(os.tmpdir(), "nvm-install.sh");
      fs.writeFileSync(scriptPath, data, { mode: 0o755 });
      var shell = getShell();
      var ok = run(shell + " " + scriptPath);
      try { fs.unlinkSync(scriptPath); } catch (e) {}
      if (!ok) {
        bail("\n  nvm install failed. See https://github.com/nvm-sh/nvm#installing-and-updating\n");
        return;
      }
      nvmDir = process.env.NVM_DIR || path.join(os.homedir(), ".nvm");
      hasNvm = true;
      console.log("");
      next();
    });
  });
}

function unixInstallNode(next) {
  ask("  Install Node.js 22 via nvm? [Y/n] ", function(a) {
    if (a === "n" || a === "no") {
      bail(
        "\n  Install manually:\n" +
        "    nvm install 22 && nvm alias default 22\n" +
        "    npm i -g open-agents-ai\n"
      );
      return;
    }
    console.log("");
    var shell = getShell();
    var cmd = 'export NVM_DIR="' + nvmDir + '" && ' +
      '[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" && ' +
      "nvm install 22 && nvm alias default 22";
    var ok = run(shell + " -c '" + cmd + "'");
    if (!ok) {
      bail("\n  Node 22 install failed.\n");
      return;
    }
    console.log("");
    next();
  });
}

// Find the Node 22 binary installed by nvm (Unix only)
function findNode22Bin() {
  var versionsDir = path.join(nvmDir, "versions", "node");
  try {
    var versions = fs.readdirSync(versionsDir).filter(function(v) {
      return v.startsWith("v22");
    }).sort().reverse();
    if (versions.length > 0) {
      var bin = path.join(versionsDir, versions[0], "bin", "node");
      try { fs.statSync(bin); return bin; } catch (e) {}
    }
  } catch (e) {}
  try {
    var shell = getShell();
    var result = childProcess.execSync(
      shell + ' -c \'export NVM_DIR="' + nvmDir + '" && [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" && nvm which 22\'',
      { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 10000 }
    ).trim();
    if (result && fs.existsSync(result)) return result;
  } catch (e) {}
  return null;
}

function unixReinstall() {
  ask("  Reinstall open-agents under Node 22? [Y/n] ", function(a) {
    if (a === "n" || a === "no") {
      console.log(
        "\n  Open a new terminal, then run:\n" +
        "    npm i -g open-agents-ai\n"
      );
      rl.close();
      process.exit(1);
      return;
    }
    console.log("");
    var shell = getShell();
    var cmd = 'export OA_SELF_UPGRADE=1 && export NVM_DIR="' + nvmDir + '" && ' +
      '[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" && ' +
      "nvm use 22 && npm i -g open-agents-ai";
    var ok = run(shell + " -c '" + cmd + "'");
    if (!ok) {
      console.log(
        "\n  Reinstall failed. Open a new terminal, then run:\n" +
        "    npm i -g open-agents-ai\n"
      );
      rl.close();
      process.exit(1);
      return;
    }
    console.log("");

    // Tell the user exactly how to launch
    var node22 = findNode22Bin();
    var binHint = node22 ? path.dirname(node22) : "~/.nvm/versions/node/v22.x.x/bin";
    console.log("  +---------------------------------------------------+");
    console.log("  |  Done! Node 22 installed + open-agents ready.     |");
    console.log("  +---------------------------------------------------+");
    console.log("");
    console.log("  To launch immediately (no new terminal needed):");
    console.log("    " + binHint + "/oa");
    console.log("");
    console.log("  Or source your shell config first:");
    var rcFile = (process.env.SHELL || "").indexOf("zsh") !== -1 ? "~/.zshrc" : "~/.bashrc";
    console.log("    source " + rcFile + " && oa");
    console.log("");
    rl.close();
    process.exit(0);
  });
}

// ── Main flow — branch on platform ───────────────────────────────────────

ask("  Install Node.js 22 now? [Y/n] ", function(a) {
  if (a === "n" || a === "no") {
    if (isWindows) {
      windowsFallbackInstructions();
    } else {
      bail(
        "\n  To install manually:\n" +
        "    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash\n" +
        "    source ~/.bashrc\n" +
        "    nvm install 22\n" +
        "    nvm alias default 22\n" +
        "    npm i -g open-agents-ai\n"
      );
    }
    return;
  }
  console.log("");

  if (isWindows) {
    windowsInstallNode(function() {
      console.log("");
      console.log("  Node.js 22 should now be available.");
      console.log("  Close and reopen your terminal, then run:");
      console.log("    npm i -g open-agents-ai");
      console.log("");
      rl.close();
      process.exit(0);
    });
  } else {
    // Unix flow: ensure downloader -> nvm -> node 22 -> reinstall
    unixInstallNvm(function() {
      unixInstallNode(function() {
        unixReinstall();
      });
    });
  }
});
