import { PACKAGE_VERSION, init_package_version } from "../package-version.js";
import { SERVICE_VERSION_ENV_KEY } from "./constants.js";
import { existsSync } from "node:fs";
import { readFile } from "node:fs/promises";
//#region src/daemon/service-audit.ts
/**
* Service Audit - Validate installed service configuration against current state
*
* Checks for:
* - Version mismatch (installed vs current)
* - Token drift (service token vs config token)
* - Missing program binary
* - Port mismatch
* - Platform-specific configuration issues
*/
init_package_version();
/** Audit installed service configuration against current config and version */
async function auditGatewayServiceConfig(params) {
	const { service, env = process.env, expectedToken, expectedPort, currentVersion = PACKAGE_VERSION } = params;
	const issues = [];
	const command = await service.readCommand(env);
	if (!command) {
		issues.push({
			code: "missing-program",
			message: "Service command configuration is not readable.",
			level: "recommended"
		});
		return {
			ok: false,
			issues
		};
	}
	auditProgramExists(command, issues);
	auditVersionMismatch(command, currentVersion, issues);
	if (expectedToken) {
		const tokenIssue = checkTokenDrift({
			serviceToken: command.environment?.[`XOPC_GATEWAY_TOKEN`],
			configToken: expectedToken
		});
		if (tokenIssue) issues.push(tokenIssue);
	}
	if (expectedPort) auditPortMismatch(command, expectedPort, issues);
	if (process.platform === "darwin" && command.sourcePath) await auditLaunchdPlist(command.sourcePath, issues);
	return {
		ok: issues.length === 0,
		issues
	};
}
function auditProgramExists(command, issues) {
	if (command.programArguments.length === 0) {
		issues.push({
			code: "missing-program",
			message: "Service has no program arguments configured.",
			level: "recommended"
		});
		return;
	}
	const program = command.programArguments[0];
	if (!existsSync(program)) issues.push({
		code: "missing-program",
		message: `Service program not found on disk: ${program}`,
		detail: program,
		level: "recommended"
	});
}
function auditVersionMismatch(command, currentVersion, issues) {
	const serviceVersion = command.environment?.[SERVICE_VERSION_ENV_KEY];
	if (!serviceVersion) return;
	if (serviceVersion !== currentVersion) issues.push({
		code: "version-mismatch",
		message: `Service version ${serviceVersion} does not match current ${currentVersion}.`,
		detail: `${serviceVersion} → ${currentVersion}`,
		level: "recommended"
	});
}
function auditPortMismatch(command, expectedPort, issues) {
	const servicePort = readCommandPort(command.programArguments);
	if (servicePort === void 0 || servicePort === expectedPort) return;
	issues.push({
		code: "port-mismatch",
		message: `Service port ${servicePort} does not match config port ${expectedPort}.`,
		detail: `${servicePort} → ${expectedPort}`,
		level: "recommended"
	});
}
async function auditLaunchdPlist(plistPath, issues) {
	try {
		const content = await readFile(plistPath, "utf8");
		const hasRunAtLoad = /<key>RunAtLoad<\/key>\s*<true\s*\/>/i.test(content);
		const hasKeepAlive = /<key>KeepAlive<\/key>/i.test(content);
		if (!hasRunAtLoad) issues.push({
			code: "launchd-run-at-load",
			message: "LaunchAgent is missing RunAtLoad=true.",
			detail: plistPath,
			level: "recommended"
		});
		if (!hasKeepAlive) issues.push({
			code: "launchd-keep-alive",
			message: "LaunchAgent is missing KeepAlive configuration.",
			detail: plistPath,
			level: "recommended"
		});
	} catch {}
}
/**
* Check if the service's embedded token differs from the config file token.
* Returns an issue if drift is detected.
*/
function checkTokenDrift(params) {
	const serviceToken = params.serviceToken?.trim();
	const configToken = params.configToken?.trim();
	if (!serviceToken) return null;
	if (!configToken) return null;
	if (serviceToken !== configToken) return {
		code: "token-drift",
		message: "Config token differs from service token. The daemon will use the old token after restart.",
		detail: "Run `xopc gateway service install --force` to sync.",
		level: "recommended"
	};
	return null;
}
function readCommandPort(programArguments) {
	for (let i = 0; i < programArguments.length; i++) {
		const arg = programArguments[i];
		if (arg === "--port" && i + 1 < programArguments.length) {
			const port = parseInt(programArguments[i + 1], 10);
			return Number.isFinite(port) && port > 0 && port <= 65535 ? port : void 0;
		}
		if (arg.startsWith("--port=")) {
			const port = parseInt(arg.slice(7), 10);
			return Number.isFinite(port) && port > 0 && port <= 65535 ? port : void 0;
		}
	}
}
//#endregion
export { auditGatewayServiceConfig, checkTokenDrift };

//# sourceMappingURL=service-audit.js.map