/**
 * Windows-safe wrapper around `pi install <pkg>`.
 *
 * Pi's own `pi.exec` calls `child_process.spawn(cmd, args, { shell: false })`,
 * which cannot launch `.cmd`/`.bat` shims on Windows — npm installs `pi` as
 * `pi.cmd`, so on Windows the spawn ENOENTs silently and the caller sees only
 * `exit 1`. We side-step it here by invoking via `cmd.exe /c` on Windows.
 */

import { spawn } from "node:child_process";

export interface PiInstallResult {
	code: number;
	stdout: string;
	stderr: string;
}

export function spawnPiInstall(pkg: string, timeoutMs: number): Promise<PiInstallResult> {
	return new Promise((resolve) => {
		const isWindows = process.platform === "win32";
		const [cmd, args, spawnOpts] = isWindows
			? (["cmd.exe", ["/c", "pi", "install", pkg], { windowsHide: true }] as const)
			: (["pi", ["install", pkg], {}] as const);

		let settled = false;
		let stdout = "";
		let stderr = "";

		const proc = spawn(cmd, args, { ...spawnOpts, stdio: ["ignore", "pipe", "pipe"] });
		proc.stdout?.on("data", (d) => {
			stdout += d.toString();
		});
		proc.stderr?.on("data", (d) => {
			stderr += d.toString();
		});

		const settle = (result: PiInstallResult) => {
			if (settled) return;
			settled = true;
			clearTimeout(timer);
			resolve(result);
		};

		const timer = setTimeout(() => {
			proc.kill("SIGTERM");
			setTimeout(() => {
				if (!proc.killed) proc.kill("SIGKILL");
			}, 5000);
			settle({ code: 124, stdout, stderr: `${stderr}\n[timed out after ${timeoutMs}ms]` });
		}, timeoutMs);

		proc.on("error", (err) => {
			settle({ code: 1, stdout, stderr: stderr + (stderr ? "\n" : "") + err.message });
		});
		proc.on("close", (code) => {
			settle({ code: code ?? 1, stdout, stderr });
		});
	});
}
