import { c as resolveGatewayLaunchAgentLabel, d as resolveGatewaySystemdServiceName } from "./constants-B0jjP2Sb.js";
import { spawnSync } from "node:child_process";

//#region src/infra/restart.ts
const SPAWN_TIMEOUT_MS = 2e3;
const SIGUSR1_AUTH_GRACE_MS = 5e3;
const DEFAULT_DEFERRAL_POLL_MS = 500;
const DEFAULT_DEFERRAL_MAX_WAIT_MS = 3e4;
let sigusr1AuthorizedCount = 0;
let sigusr1AuthorizedUntil = 0;
let sigusr1ExternalAllowed = false;
let preRestartCheck = null;
let restartCycleToken = 0;
let emittedRestartToken = 0;
let consumedRestartToken = 0;
function hasUnconsumedRestartSignal() {
	return emittedRestartToken > consumedRestartToken;
}
/**
* Register a callback that scheduleGatewaySigusr1Restart checks before emitting SIGUSR1.
* The callback should return the number of pending items (0 = safe to restart).
*/
function setPreRestartDeferralCheck(fn) {
	preRestartCheck = fn;
}
/**
* Emit an authorized SIGUSR1 gateway restart, guarded against duplicate emissions.
* Returns true if SIGUSR1 was emitted, false if a restart was already emitted.
* Both scheduleGatewaySigusr1Restart and the config watcher should use this
* to ensure only one restart fires.
*/
function emitGatewayRestart() {
	if (hasUnconsumedRestartSignal()) return false;
	emittedRestartToken = ++restartCycleToken;
	authorizeGatewaySigusr1Restart();
	try {
		if (process.listenerCount("SIGUSR1") > 0) process.emit("SIGUSR1");
		else process.kill(process.pid, "SIGUSR1");
	} catch {
		emittedRestartToken = consumedRestartToken;
		return false;
	}
	return true;
}
function resetSigusr1AuthorizationIfExpired(now = Date.now()) {
	if (sigusr1AuthorizedCount <= 0) return;
	if (now <= sigusr1AuthorizedUntil) return;
	sigusr1AuthorizedCount = 0;
	sigusr1AuthorizedUntil = 0;
}
function setGatewaySigusr1RestartPolicy(opts) {
	sigusr1ExternalAllowed = opts?.allowExternal === true;
}
function isGatewaySigusr1RestartExternallyAllowed() {
	return sigusr1ExternalAllowed;
}
function authorizeGatewaySigusr1Restart(delayMs = 0) {
	const delay = Math.max(0, Math.floor(delayMs));
	const expiresAt = Date.now() + delay + SIGUSR1_AUTH_GRACE_MS;
	sigusr1AuthorizedCount += 1;
	if (expiresAt > sigusr1AuthorizedUntil) sigusr1AuthorizedUntil = expiresAt;
}
function consumeGatewaySigusr1RestartAuthorization() {
	resetSigusr1AuthorizationIfExpired();
	if (sigusr1AuthorizedCount <= 0) return false;
	sigusr1AuthorizedCount -= 1;
	if (sigusr1AuthorizedCount <= 0) sigusr1AuthorizedUntil = 0;
	return true;
}
/**
* Mark the currently emitted SIGUSR1 restart cycle as consumed by the run loop.
* This explicitly advances the cycle state instead of resetting emit guards inside
* consumeGatewaySigusr1RestartAuthorization().
*/
function markGatewaySigusr1RestartHandled() {
	if (hasUnconsumedRestartSignal()) consumedRestartToken = emittedRestartToken;
}
/**
* Poll pending work until it drains (or times out), then emit one restart signal.
* Shared by both the direct RPC restart path and the config watcher path.
*/
function deferGatewayRestartUntilIdle(opts) {
	const pollMsRaw = opts.pollMs ?? DEFAULT_DEFERRAL_POLL_MS;
	const pollMs = Math.max(10, Math.floor(pollMsRaw));
	const maxWaitMsRaw = opts.maxWaitMs ?? DEFAULT_DEFERRAL_MAX_WAIT_MS;
	const maxWaitMs = Math.max(pollMs, Math.floor(maxWaitMsRaw));
	let pending;
	try {
		pending = opts.getPendingCount();
	} catch (err) {
		opts.hooks?.onCheckError?.(err);
		emitGatewayRestart();
		return;
	}
	if (pending <= 0) {
		opts.hooks?.onReady?.();
		emitGatewayRestart();
		return;
	}
	opts.hooks?.onDeferring?.(pending);
	const startedAt = Date.now();
	const poll = setInterval(() => {
		let current;
		try {
			current = opts.getPendingCount();
		} catch (err) {
			clearInterval(poll);
			opts.hooks?.onCheckError?.(err);
			emitGatewayRestart();
			return;
		}
		if (current <= 0) {
			clearInterval(poll);
			opts.hooks?.onReady?.();
			emitGatewayRestart();
			return;
		}
		const elapsedMs = Date.now() - startedAt;
		if (elapsedMs >= maxWaitMs) {
			clearInterval(poll);
			opts.hooks?.onTimeout?.(current, elapsedMs);
			emitGatewayRestart();
		}
	}, pollMs);
}
function formatSpawnDetail(result) {
	const clean = (value) => {
		return (typeof value === "string" ? value : value ? value.toString() : "").replace(/\s+/g, " ").trim();
	};
	if (result.error) {
		if (result.error instanceof Error) return result.error.message;
		if (typeof result.error === "string") return result.error;
		try {
			return JSON.stringify(result.error);
		} catch {
			return "unknown error";
		}
	}
	const stderr = clean(result.stderr);
	if (stderr) return stderr;
	const stdout = clean(result.stdout);
	if (stdout) return stdout;
	if (typeof result.status === "number") return `exit ${result.status}`;
	return "unknown error";
}
function normalizeSystemdUnit(raw, profile) {
	const unit = raw?.trim();
	if (!unit) return `${resolveGatewaySystemdServiceName(profile)}.service`;
	return unit.endsWith(".service") ? unit : `${unit}.service`;
}
function triggerMinionRestart() {
	if (process.env.VITEST || false) return {
		ok: true,
		method: "supervisor",
		detail: "test mode"
	};
	const tried = [];
	if (process.platform !== "darwin") {
		if (process.platform === "linux") {
			const unit = normalizeSystemdUnit(process.env.MINION_SYSTEMD_UNIT, process.env.MINION_PROFILE);
			const userArgs = [
				"--user",
				"restart",
				unit
			];
			tried.push(`systemctl ${userArgs.join(" ")}`);
			const userRestart = spawnSync("systemctl", userArgs, {
				encoding: "utf8",
				timeout: SPAWN_TIMEOUT_MS
			});
			if (!userRestart.error && userRestart.status === 0) return {
				ok: true,
				method: "systemd",
				tried
			};
			const systemArgs = ["restart", unit];
			tried.push(`systemctl ${systemArgs.join(" ")}`);
			const systemRestart = spawnSync("systemctl", systemArgs, {
				encoding: "utf8",
				timeout: SPAWN_TIMEOUT_MS
			});
			if (!systemRestart.error && systemRestart.status === 0) return {
				ok: true,
				method: "systemd",
				tried
			};
			return {
				ok: false,
				method: "systemd",
				detail: [`user: ${formatSpawnDetail(userRestart)}`, `system: ${formatSpawnDetail(systemRestart)}`].join("; "),
				tried
			};
		}
		return {
			ok: false,
			method: "supervisor",
			detail: "unsupported platform restart"
		};
	}
	const label = process.env.MINION_LAUNCHD_LABEL || resolveGatewayLaunchAgentLabel(process.env.MINION_PROFILE);
	const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
	const args = [
		"kickstart",
		"-k",
		uid !== void 0 ? `gui/${uid}/${label}` : label
	];
	tried.push(`launchctl ${args.join(" ")}`);
	const res = spawnSync("launchctl", args, {
		encoding: "utf8",
		timeout: SPAWN_TIMEOUT_MS
	});
	if (!res.error && res.status === 0) return {
		ok: true,
		method: "launchctl",
		tried
	};
	return {
		ok: false,
		method: "launchctl",
		detail: formatSpawnDetail(res),
		tried
	};
}
function scheduleGatewaySigusr1Restart(opts) {
	const delayMsRaw = typeof opts?.delayMs === "number" && Number.isFinite(opts.delayMs) ? Math.floor(opts.delayMs) : 2e3;
	const delayMs = Math.min(Math.max(delayMsRaw, 0), 6e4);
	const reason = typeof opts?.reason === "string" && opts.reason.trim() ? opts.reason.trim().slice(0, 200) : void 0;
	setTimeout(() => {
		const pendingCheck = preRestartCheck;
		if (!pendingCheck) {
			emitGatewayRestart();
			return;
		}
		deferGatewayRestartUntilIdle({ getPendingCount: pendingCheck });
	}, delayMs);
	return {
		ok: true,
		pid: process.pid,
		signal: "SIGUSR1",
		delayMs,
		reason,
		mode: process.listenerCount("SIGUSR1") > 0 ? "emit" : "signal"
	};
}

//#endregion
export { markGatewaySigusr1RestartHandled as a, setPreRestartDeferralCheck as c, isGatewaySigusr1RestartExternallyAllowed as i, triggerMinionRestart as l, deferGatewayRestartUntilIdle as n, scheduleGatewaySigusr1Restart as o, emitGatewayRestart as r, setGatewaySigusr1RestartPolicy as s, consumeGatewaySigusr1RestartAuthorization as t };