#!/usr/bin/env node
// Entry point for the Codex CLI.
// Resolves the platform binary from:
//   1. Optional sub-package: makecoder-codex-<platform>  (installed via optionalDependencies)
//   2. Local fallback: same directory as this script      (dev / legacy layout)

import { spawn } from "node:child_process";
import { existsSync } from "fs";
import { createRequire } from "node:module";
import path from "path";
import { fileURLToPath } from "url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const require = createRequire(import.meta.url);

const PLATFORM_PACKAGE = {
  "linux-x64":    "makecoder-codex-linux-x64",
  "darwin-arm64": "makecoder-codex-darwin-arm64",
  "win32-x64":    "makecoder-codex-win32-x64",
};

const { platform, arch } = process;
const platformKey = `${platform}-${arch}`;
const codexBinaryName = platform === "win32" ? "codex.exe" : "codex";

if (!PLATFORM_PACKAGE[platformKey]) {
  throw new Error(`Unsupported platform: ${platform} (${arch})`);
}

const platformPackage = PLATFORM_PACKAGE[platformKey];

// 1. Try optional sub-package
let binaryPath = null;
try {
  const pkgJsonPath = require.resolve(`${platformPackage}/package.json`);
  const candidate = path.join(path.dirname(pkgJsonPath), "bin", codexBinaryName);
  if (existsSync(candidate)) {
    binaryPath = candidate;
  }
} catch {
  // sub-package not installed
}

// 2. Fallback: binary alongside this script (dist/ in legacy or dev layout)
if (!binaryPath) {
  const localCandidate = path.join(__dirname, codexBinaryName);
  if (existsSync(localCandidate)) {
    binaryPath = localCandidate;
  }
}

if (!binaryPath) {
  throw new Error(
    `Codex binary not found for ${platformKey}.\n` +
    `Expected sub-package ${platformPackage} to be installed.\n` +
    `Try reinstalling: npm install -g makecoder@latest`
  );
}

// ---- process helpers ----

function detectPackageManager() {
  const userAgent = process.env.npm_config_user_agent || "";
  if (/\bbun\//.test(userAgent)) return "bun";
  const execPath = process.env.npm_execpath || "";
  if (execPath.includes("bun")) return "bun";
  if (__dirname.includes(".bun/install/global") || __dirname.includes(".bun\\install\\global")) return "bun";
  return userAgent ? "npm" : null;
}

const env = { ...process.env };
env[detectPackageManager() === "bun" ? "CODEX_MANAGED_BY_BUN" : "CODEX_MANAGED_BY_NPM"] = "1";

const child = spawn(binaryPath, process.argv.slice(2), { stdio: "inherit", env });

child.on("error", (err) => {
  console.error(err);
  process.exit(1);
});

const forwardSignal = (signal) => {
  if (child.killed) return;
  try { child.kill(signal); } catch { /* ignore */ }
};
["SIGINT", "SIGTERM", "SIGHUP"].forEach((sig) => process.on(sig, () => forwardSignal(sig)));

const childResult = await new Promise((resolve) => {
  child.on("exit", (code, signal) => {
    resolve(signal ? { type: "signal", signal } : { type: "code", exitCode: code ?? 1 });
  });
});

if (childResult.type === "signal") {
  process.kill(process.pid, childResult.signal);
} else {
  process.exit(childResult.exitCode);
}
