import { createDefaultCommandRunner } from "./run-command.js";
import fs from "node:fs";
import fs$1 from "node:fs/promises";
import path from "node:path";
//#region src/infra/update-global.ts
const XOPC_PACKAGE_NAME = "@xopcai/xopc";
const COREPACK_ENABLE_DOWNLOAD_PROMPT_DEFAULT = "0";
const NPM_GLOBAL_INSTALL_QUIET_FLAGS = [
	"--no-fund",
	"--no-audit",
	"--loglevel=error"
];
const NPM_GLOBAL_INSTALL_OMIT_OPTIONAL_FLAGS = ["--omit=optional", ...NPM_GLOBAL_INSTALL_QUIET_FLAGS];
const GLOBAL_DETECT_TIMEOUT_MS = 15e3;
const GLOBAL_INSTALL_TIMEOUT_MS = 2700 * 1e3;
async function pathExists(targetPath) {
	try {
		await fs$1.access(targetPath);
		return true;
	} catch {
		return false;
	}
}
async function tryRealpath(targetPath) {
	try {
		return await fs$1.realpath(targetPath);
	} catch {
		return path.resolve(targetPath);
	}
}
function joinGlobalPackagePath(globalRoot) {
	return path.join(globalRoot, XOPC_PACKAGE_NAME);
}
function inferNpmPrefixFromPackageRoot(pkgRoot) {
	const trimmed = pkgRoot?.trim();
	if (!trimmed) return null;
	const normalized = path.resolve(trimmed);
	const nodeModulesDir = path.dirname(normalized);
	if (path.basename(nodeModulesDir) !== "node_modules") return null;
	const parentDir = path.dirname(nodeModulesDir);
	if (path.basename(parentDir) === "lib") return path.dirname(parentDir);
	if (process.platform === "win32" && path.basename(parentDir).toLowerCase() === "npm") return parentDir;
	return null;
}
function resolvePreferredNpmCommand(pkgRoot) {
	const prefix = inferNpmPrefixFromPackageRoot(pkgRoot);
	if (!prefix) return null;
	const candidate = process.platform === "win32" ? path.join(prefix, "npm.cmd") : path.join(prefix, "bin", "npm");
	return fs.existsSync(candidate) ? candidate : null;
}
function resolvePreferredGlobalManagerCommand(manager, pkgRoot) {
	if (manager !== "npm") return manager;
	return resolvePreferredNpmCommand(pkgRoot) ?? manager;
}
function resolveGlobalInstallCommand(manager, pkgRoot) {
	return {
		manager,
		command: resolvePreferredGlobalManagerCommand(manager, pkgRoot)
	};
}
function normalizeGlobalInstallCommand(managerOrCommand, pkgRoot) {
	return typeof managerOrCommand === "string" ? resolveGlobalInstallCommand(managerOrCommand, pkgRoot) : managerOrCommand;
}
function applyWindowsPackageInstallEnv(env) {
	if (process.platform !== "win32") return;
	env.NPM_CONFIG_UPDATE_NOTIFIER = "false";
	env.NPM_CONFIG_FUND = "false";
	env.NPM_CONFIG_AUDIT = "false";
}
function applyCorepackDownloadPromptEnv(env) {
	if (!env.COREPACK_ENABLE_DOWNLOAD_PROMPT?.trim()) env.COREPACK_ENABLE_DOWNLOAD_PROMPT = COREPACK_ENABLE_DOWNLOAD_PROMPT_DEFAULT;
}
async function createGlobalInstallEnv(env) {
	const sourceEnv = env ?? process.env;
	const hasCorepack = Boolean(sourceEnv.COREPACK_ENABLE_DOWNLOAD_PROMPT?.trim());
	if (process.platform !== "win32" && hasCorepack) return env;
	const merged = Object.fromEntries(Object.entries(sourceEnv).filter(([, value]) => value != null).map(([key, value]) => [key, String(value)]));
	applyWindowsPackageInstallEnv(merged);
	applyCorepackDownloadPromptEnv(merged);
	return merged;
}
function resolveGlobalInstallSpec(params) {
	const override = params.env?.XOPC_UPDATE_PACKAGE_SPEC?.trim() || process.env.XOPC_UPDATE_PACKAGE_SPEC?.trim();
	if (override) return override;
	return `${XOPC_PACKAGE_NAME}@${params.version}`;
}
async function resolveGlobalRoot(managerOrCommand, runCommand, timeoutMs, pkgRoot) {
	const res = await runCommand([
		normalizeGlobalInstallCommand(managerOrCommand, pkgRoot).command,
		"root",
		"-g"
	], { timeoutMs }).catch(() => null);
	if (!res || res.code !== 0) return null;
	return res.stdout.trim() || null;
}
function globalInstallArgs(managerOrCommand, spec, pkgRoot) {
	const resolved = normalizeGlobalInstallCommand(managerOrCommand, pkgRoot);
	if (resolved.manager === "pnpm") return [
		resolved.command,
		"add",
		"-g",
		spec
	];
	return [
		resolved.command,
		"install",
		"-g",
		spec,
		...NPM_GLOBAL_INSTALL_QUIET_FLAGS
	];
}
function globalInstallFallbackArgs(managerOrCommand, spec, pkgRoot) {
	const resolved = normalizeGlobalInstallCommand(managerOrCommand, pkgRoot);
	if (resolved.manager !== "npm") return null;
	return [
		resolved.command,
		"install",
		"-g",
		spec,
		...NPM_GLOBAL_INSTALL_OMIT_OPTIONAL_FLAGS
	];
}
async function detectGlobalInstallManagerForRoot(runCommand, pkgRoot, timeoutMs) {
	const pkgReal = await tryRealpath(pkgRoot);
	for (const { manager, argv } of [{
		manager: "npm",
		argv: [
			"npm",
			"root",
			"-g"
		]
	}, {
		manager: "pnpm",
		argv: [
			"pnpm",
			"root",
			"-g"
		]
	}]) {
		const res = await runCommand(argv, { timeoutMs }).catch(() => null);
		if (!res || res.code !== 0) continue;
		const globalRoot = res.stdout.trim();
		if (!globalRoot) continue;
		const expectedReal = await tryRealpath(joinGlobalPackagePath(await tryRealpath(globalRoot)));
		if (path.resolve(expectedReal) === path.resolve(pkgReal)) return manager;
	}
	if (resolvePreferredNpmCommand(pkgRoot)) return "npm";
	return null;
}
async function detectGlobalInstallManagerByPresence(runCommand, timeoutMs) {
	for (const manager of ["npm", "pnpm"]) {
		const root = await resolveGlobalRoot(manager, runCommand, timeoutMs);
		if (!root) continue;
		if (await pathExists(joinGlobalPackagePath(root))) return manager;
	}
	return null;
}
async function resolveGlobalManager(params) {
	const runCommand = createDefaultCommandRunner();
	const timeoutMs = params.timeoutMs ?? GLOBAL_DETECT_TIMEOUT_MS;
	if (params.root) {
		const detected = await detectGlobalInstallManagerForRoot(runCommand, params.root, timeoutMs);
		if (detected) return detected;
	}
	return await detectGlobalInstallManagerByPresence(runCommand, timeoutMs) ?? "npm";
}
function tailOutput(text, max = 4e3) {
	const t = text.trim();
	if (t.length <= max) return t;
	return t.slice(-max);
}
async function runGlobalPackageInstall(params) {
	const timeoutMs = params.timeoutMs ?? GLOBAL_INSTALL_TIMEOUT_MS;
	const runCommand = createDefaultCommandRunner();
	const installEnv = await createGlobalInstallEnv();
	const runStep = async (argv) => {
		const result = await runCommand(argv, {
			timeoutMs,
			env: installEnv
		});
		if (params.echoToTerminal) {
			if (result.stdout) process.stdout.write(result.stdout);
			if (result.stderr) process.stderr.write(result.stderr);
		}
		return result;
	};
	const primary = await runStep(globalInstallArgs(params.manager, params.spec, params.pkgRoot));
	if (primary.code === 0) return {
		exitCode: 0,
		stdout: primary.stdout,
		stderr: primary.stderr,
		packageManager: params.manager,
		usedFallback: false
	};
	const fallbackArgv = globalInstallFallbackArgs(params.manager, params.spec, params.pkgRoot);
	if (!fallbackArgv) return {
		exitCode: primary.code ?? 1,
		stdout: primary.stdout,
		stderr: primary.stderr,
		packageManager: params.manager,
		usedFallback: false
	};
	const fallback = await runStep(fallbackArgv);
	return {
		exitCode: fallback.code ?? 1,
		stdout: [primary.stdout, fallback.stdout].filter(Boolean).join("\n"),
		stderr: [primary.stderr, fallback.stderr].filter(Boolean).join("\n"),
		packageManager: params.manager,
		usedFallback: true
	};
}
function formatGlobalInstallFailure(params) {
	const tail = tailOutput(params.stderr);
	return [
		`Global install via ${params.packageManager} failed (exit ${params.exitCode}).`,
		params.usedFallback ? "Retried with --omit=optional." : null,
		`Try manually: ${params.packageManager} install -g ${params.spec}`,
		tail ? `Install output:\n${tail}` : null
	].filter(Boolean).join("\n");
}
//#endregion
export { XOPC_PACKAGE_NAME, createGlobalInstallEnv, detectGlobalInstallManagerByPresence, detectGlobalInstallManagerForRoot, formatGlobalInstallFailure, globalInstallArgs, globalInstallFallbackArgs, joinGlobalPackagePath, resolveGlobalInstallCommand, resolveGlobalInstallSpec, resolveGlobalManager, resolveGlobalRoot, runGlobalPackageInstall };

//# sourceMappingURL=update-global.js.map