import { y as sleep } from "./utils-CTPsqyE_.js";
import { o as resolveLsofCommandSync } from "./ports-gxLM5ahL.js";
import { execFileSync } from "node:child_process";

//#region src/cli/ports.ts
function parseLsofOutput(output) {
	const lines = output.split(/\r?\n/).filter(Boolean);
	const results = [];
	let current = {};
	for (const line of lines) if (line.startsWith("p")) {
		if (current.pid) results.push(current);
		current = { pid: Number.parseInt(line.slice(1), 10) };
	} else if (line.startsWith("c")) current.command = line.slice(1);
	if (current.pid) results.push(current);
	return results;
}
function listPortListeners(port) {
	try {
		return parseLsofOutput(execFileSync(resolveLsofCommandSync(), [
			"-nP",
			`-iTCP:${port}`,
			"-sTCP:LISTEN",
			"-FpFc"
		], { encoding: "utf-8" }));
	} catch (err) {
		const status = err.status;
		if (err.code === "ENOENT") throw new Error("lsof not found; required for --force", { cause: err });
		if (status === 1) return [];
		throw err instanceof Error ? err : new Error(String(err));
	}
}
function forceFreePort(port) {
	const listeners = listPortListeners(port);
	for (const proc of listeners) try {
		process.kill(proc.pid, "SIGTERM");
	} catch (err) {
		throw new Error(`failed to kill pid ${proc.pid}${proc.command ? ` (${proc.command})` : ""}: ${String(err)}`, { cause: err });
	}
	return listeners;
}
function killPids(listeners, signal) {
	for (const proc of listeners) try {
		process.kill(proc.pid, signal);
	} catch (err) {
		throw new Error(`failed to kill pid ${proc.pid}${proc.command ? ` (${proc.command})` : ""}: ${String(err)}`, { cause: err });
	}
}
async function forceFreePortAndWait(port, opts = {}) {
	const timeoutMs = Math.max(opts.timeoutMs ?? 1500, 0);
	const intervalMs = Math.max(opts.intervalMs ?? 100, 1);
	const sigtermTimeoutMs = Math.min(Math.max(opts.sigtermTimeoutMs ?? 600, 0), timeoutMs);
	const killed = forceFreePort(port);
	if (killed.length === 0) return {
		killed,
		waitedMs: 0,
		escalatedToSigkill: false
	};
	let waitedMs = 0;
	const triesSigterm = intervalMs > 0 ? Math.ceil(sigtermTimeoutMs / intervalMs) : 0;
	for (let i = 0; i < triesSigterm; i++) {
		if (listPortListeners(port).length === 0) return {
			killed,
			waitedMs,
			escalatedToSigkill: false
		};
		await sleep(intervalMs);
		waitedMs += intervalMs;
	}
	if (listPortListeners(port).length === 0) return {
		killed,
		waitedMs,
		escalatedToSigkill: false
	};
	killPids(listPortListeners(port), "SIGKILL");
	const remainingBudget = Math.max(timeoutMs - waitedMs, 0);
	const triesSigkill = intervalMs > 0 ? Math.ceil(remainingBudget / intervalMs) : 0;
	for (let i = 0; i < triesSigkill; i++) {
		if (listPortListeners(port).length === 0) return {
			killed,
			waitedMs,
			escalatedToSigkill: true
		};
		await sleep(intervalMs);
		waitedMs += intervalMs;
	}
	const still = listPortListeners(port);
	if (still.length === 0) return {
		killed,
		waitedMs,
		escalatedToSigkill: true
	};
	throw new Error(`port ${port} still has listeners after --force: ${still.map((p) => p.pid).join(", ")}`);
}

//#endregion
export { forceFreePortAndWait as t };