import { execFile } from "child_process";
import { promisify } from "util";
import { existsSync } from "fs";
import { dirname, join } from "path";
import { execPath } from "process";

const execFileAsync = promisify(execFile);

const piCache = { path: null as string | null };

/**
 * Locate the `pi` CLI binary.
 *
 * Checks PATH first (via `which pi`), then falls back to known install
 * locations (Homebrew, npm global, etc.).
 */
async function findPiPath(): Promise<string> {
  if (piCache.path) return piCache.path;

  // Check PATH
  try {
    const { stdout } = await execFileAsync("which", ["pi"]);
    const p = stdout.trim();
    if (p && existsSync(p)) {
      piCache.path = p;
      return p;
    }
  } catch {
    // not on PATH
  }

  // Common install locations
  const candidates = [
    "/opt/homebrew/bin/pi",
    "/usr/local/bin/pi",
    "/usr/bin/pi",
    // npm global installs
    join(dirname(execPath), "pi"),
    join(dirname(execPath), "..", "lib", "node_modules", "@earendil-works", "pi-coding-agent", "cli", "pi.js"),
  ];
  for (const p of candidates) {
    try {
      if (existsSync(p)) {
        piCache.path = p;
        return p;
      }
    } catch {
      // ignore
    }
  }

  throw new Error("pi CLI not found. Install it from https://pi.dev");
}

export interface RunPiOptions {
  timeout?: number;
  cwd?: string;
}

/**
 * Run a `pi` CLI command and return stdout/stderr.
 * Never uses a shell, so user-supplied args are never interpreted as shell syntax.
 */
export async function runPi(args: string[], opts: RunPiOptions = {}): Promise<{ stdout: string; stderr: string }> {
  const piPath = await findPiPath();
  const result = await execFileAsync(piPath, args, {
    timeout: opts.timeout ?? 60000,
    cwd: opts.cwd,
    env: { ...process.env, FORCE_COLOR: "0" },
  });
  return { stdout: result.stdout, stderr: result.stderr };
}
