import { createLogger } from "../../../utils/logger/index.js";
import { init_logger } from "../../../utils/logger.js";
import { formatPortDiagnostics, inspectPortUsage } from "../../../infra/ports.js";
//#region src/cli/commands/gateway/restart-health.ts
init_logger();
const log = createLogger("RestartHealth");
const DEFAULT_RESTART_HEALTH_TIMEOUT_MS = 6e4;
const DEFAULT_RESTART_HEALTH_DELAY_MS = 500;
const DEFAULT_RESTART_HEALTH_ATTEMPTS = Math.ceil(DEFAULT_RESTART_HEALTH_TIMEOUT_MS / 500);
/**
* Wait for gateway restart to complete and verify health.
*
* Loop:
* 1. Check service runtime → get PID
* 2. inspectPortUsage → confirm port is busy with new process
* 3. HTTP probe /api/health → confirm reachable
* 4. Version match (if expectedVersion provided)
*/
async function waitForRestartHealth(params) {
	const { service, port, expectedVersion, timeoutMs = DEFAULT_RESTART_HEALTH_TIMEOUT_MS, delayMs = 500, token, onProgress } = params;
	const { inspectPortUsage, classifyPortListener } = await import("../../../infra/ports.js");
	const startedAt = Date.now();
	while (Date.now() - startedAt < timeoutMs) {
		const elapsed = Date.now() - startedAt;
		const runtime = await service.readRuntime();
		if (runtime.status !== "running" || !runtime.pid) {
			onProgress?.({
				runtime,
				healthy: false,
				staleGatewayPids: [],
				elapsedMs: elapsed
			});
			await sleep(delayMs);
			continue;
		}
		const portUsage = await inspectPortUsage(port);
		if (portUsage.status !== "busy") {
			onProgress?.({
				runtime,
				portUsage,
				healthy: false,
				staleGatewayPids: [],
				elapsedMs: elapsed
			});
			await sleep(delayMs);
			continue;
		}
		const gatewayListeners = portUsage.listeners.filter((l) => classifyPortListener(l, runtime.pid) === "gateway");
		const staleGatewayPids = portUsage.listeners.filter((l) => l.pid && l.pid !== runtime.pid && classifyPortListener(l) === "gateway").map((l) => l.pid).filter(Boolean);
		if (gatewayListeners.length === 0) {
			onProgress?.({
				runtime,
				portUsage,
				healthy: false,
				staleGatewayPids,
				elapsedMs: elapsed
			});
			await sleep(delayMs);
			continue;
		}
		const healthResult = await probeHealth(port, token);
		if (!healthResult.ok) {
			onProgress?.({
				runtime,
				portUsage,
				healthy: false,
				staleGatewayPids,
				elapsedMs: elapsed
			});
			await sleep(delayMs);
			continue;
		}
		const gatewayVersion = healthResult.version ?? null;
		if (expectedVersion && gatewayVersion && gatewayVersion !== expectedVersion) {
			const snapshot = {
				runtime,
				portUsage,
				healthy: false,
				staleGatewayPids,
				gatewayVersion,
				expectedVersion,
				versionMismatch: {
					expected: expectedVersion,
					actual: gatewayVersion
				},
				waitOutcome: "version-mismatch",
				elapsedMs: elapsed
			};
			onProgress?.(snapshot);
			return snapshot;
		}
		const snapshot = {
			runtime,
			portUsage,
			healthy: true,
			staleGatewayPids,
			gatewayVersion,
			expectedVersion,
			waitOutcome: "healthy",
			elapsedMs: elapsed
		};
		onProgress?.(snapshot);
		log.info({
			pid: runtime.pid,
			elapsedMs: elapsed,
			port
		}, "Restart health confirmed");
		return snapshot;
	}
	const finalSnapshot = {
		runtime: await service.readRuntime(),
		healthy: false,
		staleGatewayPids: [],
		waitOutcome: "timeout",
		elapsedMs: Date.now() - startedAt
	};
	log.warn({
		timeoutMs,
		port
	}, "Restart health check timed out");
	return finalSnapshot;
}
async function probeHealth(port, token) {
	try {
		const headers = {};
		if (token) headers["Authorization"] = `Bearer ${token}`;
		const controller = new AbortController();
		const timeout = setTimeout(() => controller.abort(), 3e3);
		const response = await fetch(`http://127.0.0.1:${port}/api/health`, {
			method: "GET",
			headers,
			signal: controller.signal
		});
		clearTimeout(timeout);
		if (!response.ok) return {
			ok: false,
			error: `HTTP ${response.status}`
		};
		return {
			ok: true,
			version: (await response.json()).version
		};
	} catch (err) {
		return {
			ok: false,
			error: err instanceof Error ? err.message : String(err)
		};
	}
}
function sleep(ms) {
	return new Promise((resolve) => setTimeout(resolve, ms));
}
async function inspectGatewayPortHealth(port, token) {
	let portUsage;
	try {
		portUsage = await inspectPortUsage(port);
	} catch (err) {
		portUsage = {
			port,
			status: "unknown",
			listeners: [],
			hints: [],
			errors: [String(err)]
		};
	}
	let healthy = false;
	if (portUsage.status === "busy") healthy = (await probeHealth(port, token)).ok;
	return {
		portUsage,
		healthy
	};
}
async function waitForGatewayHealthyListener(params) {
	const attempts = params.attempts ?? DEFAULT_RESTART_HEALTH_ATTEMPTS;
	const delayMs = params.delayMs ?? 500;
	let snapshot = await inspectGatewayPortHealth(params.port, params.token);
	for (let attempt = 0; attempt < attempts; attempt += 1) {
		if (snapshot.healthy) return snapshot;
		await sleep(delayMs);
		snapshot = await inspectGatewayPortHealth(params.port, params.token);
	}
	return snapshot;
}
function renderGatewayPortHealthDiagnostics(snapshot) {
	const lines = [];
	if (!snapshot.portUsage) {
		lines.push("Gateway port health unavailable.");
		return lines;
	}
	if (snapshot.portUsage.status === "busy") lines.push(...formatPortDiagnostics(snapshot.portUsage));
	else lines.push(`Gateway port ${snapshot.portUsage.port} status: ${snapshot.portUsage.status}.`);
	if (snapshot.portUsage.errors?.length) lines.push(`Port diagnostics errors: ${snapshot.portUsage.errors.join("; ")}`);
	return lines;
}
//#endregion
export { DEFAULT_RESTART_HEALTH_ATTEMPTS, DEFAULT_RESTART_HEALTH_DELAY_MS, DEFAULT_RESTART_HEALTH_TIMEOUT_MS, renderGatewayPortHealthDiagnostics, waitForGatewayHealthyListener, waitForRestartHealth };

//# sourceMappingURL=restart-health.js.map