import { createLogger } from "../utils/logger/index.js";
import { init_logger } from "../utils/logger.js";
import { resolveGatewaySystemdServiceName, resolveSystemdUnitPath } from "./constants.js";
import { existsSync } from "node:fs";
import { access, constants as constants$1, mkdir, readFile, rm, writeFile } from "node:fs/promises";
import path from "node:path";
import os from "node:os";
import { spawn, spawnSync } from "node:child_process";
//#region src/daemon/systemd.ts
/**
* Systemd Service - Linux user service management
*
* Aligned with OpenClaw systemd implementation:
* - Restart=always with RestartPreventExitStatus=78
* - StartLimitBurst/StartLimitIntervalSec for rate limiting
* - KillMode=control-group
* - network-online.target dependency
*/
init_logger();
const log = createLogger("SystemdService");
function resolveProfileFromEnv(env) {
	return env?.XOPC_PROFILE?.trim() || void 0;
}
function resolveServiceName(env) {
	return resolveGatewaySystemdServiceName(resolveProfileFromEnv(env));
}
function resolveSystemdUserUnitPath(env) {
	return resolveSystemdUnitPath(resolveProfileFromEnv(env));
}
function escapeSystemdUnitValue(value) {
	return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/%/g, "%%");
}
function quoteSystemdExecArg(arg) {
	const escapedArg = escapeSystemdUnitValue(arg);
	if (/^[A-Za-z0-9_@%+=:,./-]+$/.test(arg)) return escapedArg;
	return `"${escapedArg}"`;
}
function buildSystemdUnit(params) {
	const envLines = Object.entries(params.environment).map(([key, value]) => `Environment="${key}=${escapeSystemdUnitValue(value)}"`).join("\n");
	const execStart = params.programArguments.map(quoteSystemdExecArg).join(" ");
	let unit = `[Unit]
Description=${params.description}
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=${execStart}
`;
	if (params.workingDirectory) unit += `WorkingDirectory=${params.workingDirectory}\n`;
	if (envLines) unit += `${envLines}\n`;
	unit += `Restart=always
RestartSec=5
RestartPreventExitStatus=78
KillMode=control-group
StartLimitBurst=5
StartLimitIntervalSec=60

[Install]
WantedBy=default.target
`;
	return unit;
}
async function systemctl(args) {
	return new Promise((resolve, reject) => {
		const child = spawn("systemctl", ["--user", ...args], { stdio: [
			"ignore",
			"pipe",
			"pipe"
		] });
		let stdout = "";
		let stderr = "";
		child.stdout?.on("data", (data) => {
			stdout += data.toString();
		});
		child.stderr?.on("data", (data) => {
			stderr += data.toString();
		});
		child.on("close", (code) => {
			resolve({
				stdout,
				stderr,
				exitCode: code
			});
		});
		child.on("error", (err) => {
			reject(/* @__PURE__ */ new Error(`systemctl spawn failed: ${err.message}`));
		});
	});
}
async function systemctlExec(args) {
	const result = await systemctl(args);
	if (result.exitCode !== 0) {
		const detail = result.stderr.trim() || result.stdout.trim();
		throw new Error(`systemctl ${args.join(" ")} failed (exit ${result.exitCode}): ${detail}`);
	}
}
function isSystemdAvailable() {
	if (process.platform !== "linux") return false;
	try {
		return spawnSync("systemctl", ["--user", "--version"], {
			stdio: [
				"ignore",
				"pipe",
				"ignore"
			],
			timeout: 3e3
		}).status === 0;
	} catch {
		return false;
	}
}
function getUsername() {
	return os.userInfo().username;
}
async function isLingerEnabled() {
	try {
		await access(`/var/lib/systemd/linger/${getUsername()}`, constants$1.F_OK);
		return true;
	} catch {
		return false;
	}
}
async function enableLinger() {
	if (!isSystemdAvailable()) throw new Error("systemd is not available");
	if (await isLingerEnabled()) {
		log.info("User lingering already enabled");
		return;
	}
	if (spawnSync("loginctl", ["enable-linger", getUsername()], {
		stdio: [
			"ignore",
			"pipe",
			"pipe"
		],
		timeout: 5e3
	}).status !== 0) {
		log.warn({ command: `loginctl enable-linger ${getUsername()}` }, "Failed to enable systemd user linger; gateway may not survive logout");
		throw new Error(`Failed to enable user lingering. Run: sudo loginctl enable-linger ${getUsername()}`);
	}
	log.info("Enabled user lingering");
}
function parseUnitEnvironment(content) {
	const environment = {};
	const matches = content.matchAll(/^Environment="([^=]+)=(.*)"/gm);
	for (const match of matches) environment[match[1]] = match[2];
	return environment;
}
const systemdService = {
	label: resolveGatewaySystemdServiceName(),
	loadedText: "systemd (enabled)",
	notLoadedText: "systemd (not installed)",
	async install(args) {
		const serviceName = resolveServiceName(args.env);
		const unitPath = resolveSystemdUserUnitPath(args.env);
		await mkdir(path.dirname(unitPath), { recursive: true });
		const environment = {};
		if (args.environment) Object.assign(environment, args.environment);
		await writeFile(unitPath, buildSystemdUnit({
			description: args.description || "xopc Gateway Service",
			programArguments: args.programArguments,
			workingDirectory: args.workingDirectory,
			environment
		}), "utf8");
		args.stdout?.write(`Written: ${unitPath}\n`);
		await systemctlExec(["daemon-reload"]);
		await systemctlExec(["enable", serviceName]);
		try {
			await enableLinger();
		} catch (err) {
			const message = err instanceof Error ? err.message : String(err);
			args.stdout?.write(`Warning: ${message}\n`);
			log.warn({ err }, "Systemd user linger is not enabled; gateway may stop after logout");
		}
		log.info({
			serviceName,
			unitPath
		}, "Systemd service installed and enabled");
	},
	async uninstall(args) {
		const serviceName = resolveServiceName(args.env);
		const unitPath = resolveSystemdUserUnitPath(args.env);
		try {
			await systemctlExec(["stop", serviceName]);
		} catch {}
		try {
			await systemctlExec(["disable", serviceName]);
		} catch {}
		if (existsSync(unitPath)) {
			await rm(unitPath);
			args.stdout?.write(`Removed: ${unitPath}\n`);
		}
		await systemctlExec(["daemon-reload"]);
		log.info({
			serviceName,
			unitPath
		}, "Systemd service uninstalled");
	},
	async stop(args) {
		const serviceName = resolveServiceName(args.env);
		if (args.disable) {
			await systemctlExec(["stop", serviceName]);
			await systemctlExec(["disable", serviceName]);
			log.info("Systemd service stopped and disabled");
		} else {
			await systemctlExec(["stop", serviceName]);
			log.info("Systemd service stopped");
		}
	},
	async restart(args) {
		await systemctlExec(["restart", resolveServiceName(args.env)]);
		log.info("Systemd service restarted");
		return { outcome: "restarted" };
	},
	async isLoaded(args) {
		return (await systemctl(["is-enabled", resolveServiceName(args.env)])).exitCode === 0;
	},
	async readRuntime(env) {
		const serviceName = resolveServiceName(env);
		try {
			const result = await systemctl([
				"show",
				serviceName,
				"--property=ActiveState,MainPID,ExecMainStatus"
			]);
			if (result.exitCode !== 0) return { status: "unknown" };
			const lines = result.stdout.trim().split("\n");
			let status = "unknown";
			let pid;
			let lastExitStatus;
			for (const line of lines) {
				const eqIdx = line.indexOf("=");
				if (eqIdx < 0) continue;
				const key = line.slice(0, eqIdx);
				const value = line.slice(eqIdx + 1);
				if (key === "ActiveState") status = value === "active" ? "running" : value === "inactive" ? "stopped" : "unknown";
				else if (key === "MainPID") {
					const parsed = parseInt(value, 10);
					if (parsed > 0) pid = parsed;
				} else if (key === "ExecMainStatus") lastExitStatus = parseInt(value, 10);
			}
			return {
				status,
				pid,
				lastExitStatus
			};
		} catch {
			return { status: "unknown" };
		}
	},
	async readCommand(env) {
		const unitPath = resolveSystemdUserUnitPath(env);
		if (!existsSync(unitPath)) return null;
		const content = await readFile(unitPath, "utf8");
		const execStartMatch = content.match(/^ExecStart=(.+)$/m);
		const workDirMatch = content.match(/^WorkingDirectory=(.+)$/m);
		if (!execStartMatch) return null;
		const programArguments = execStartMatch[1].trim().split(/\s+/);
		const environment = parseUnitEnvironment(content);
		return {
			programArguments,
			workingDirectory: workDirMatch?.[1],
			environment,
			sourcePath: unitPath
		};
	}
};
//#endregion
export { buildSystemdUnit, enableLinger, isSystemdAvailable, resolveSystemdUserUnitPath, systemdService };

//# sourceMappingURL=systemd.js.map