/**
 * Tracks the PID of a Gateway process spawned by this 4Runr CLI session (TUI connect autostart).
 * Used before global npm updates on Windows so `apps/gateway` is not locked (EBUSY).
 */
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { findListeningPidWindows, getWindowsProcessImageName, killPidTreeWindows, } from './win-port-pid.js';
export const LOCAL_GATEWAY_PID_FILENAME = '4runr-os-local-gateway.pid';
/** Default local Gateway HTTP port when URL has no explicit port */
export const DEFAULT_LOCAL_GATEWAY_PORT = 3001;
/**
 * Port to use when stopping the local Gateway on exit — matches `GATEWAY_URL` when it points at localhost.
 */
export function resolveLocalGatewayShutdownPort() {
    const raw = String(process.env.GATEWAY_URL || '').trim();
    if (!raw)
        return DEFAULT_LOCAL_GATEWAY_PORT;
    try {
        const parsed = new URL(raw);
        const host = parsed.hostname.toLowerCase();
        const local = host === 'localhost' ||
            host === '127.0.0.1' ||
            host === '::1' ||
            host === '0.0.0.0';
        if (!local)
            return DEFAULT_LOCAL_GATEWAY_PORT;
        if (parsed.port)
            return parseInt(parsed.port, 10);
        return DEFAULT_LOCAL_GATEWAY_PORT;
    }
    catch {
        return DEFAULT_LOCAL_GATEWAY_PORT;
    }
}
export function localGatewayPidFilePath() {
    return path.join(os.tmpdir(), LOCAL_GATEWAY_PID_FILENAME);
}
export function writeLocalGatewayPid(pid) {
    if (!Number.isFinite(pid) || pid <= 0)
        return;
    try {
        fs.writeFileSync(localGatewayPidFilePath(), String(pid), 'utf-8');
    }
    catch {
        /* ignore */
    }
}
export function clearLocalGatewayPidFile() {
    try {
        fs.unlinkSync(localGatewayPidFilePath());
    }
    catch {
        /* ignore */
    }
}
export function readLocalGatewayPid() {
    try {
        const raw = fs.readFileSync(localGatewayPidFilePath(), 'utf-8').trim();
        const n = parseInt(raw, 10);
        return Number.isFinite(n) && n > 0 ? n : null;
    }
    catch {
        return null;
    }
}
function killPidRecordedInFile() {
    const pid = readLocalGatewayPid();
    if (pid == null)
        return;
    try {
        process.kill(pid, 0);
    }
    catch {
        clearLocalGatewayPidFile();
        return;
    }
    if (process.platform === 'win32') {
        killPidTreeWindows(pid);
    }
    else {
        try {
            process.kill(pid, 'SIGTERM');
        }
        catch {
            /* ignore */
        }
    }
    clearLocalGatewayPidFile();
}
/**
 * If the PID file is stale (npm exited but Node still listens), stop the listener on `port`.
 * Only kills when the owning image looks like Node — avoids killing unrelated servers on 3001.
 */
export function killLocalGatewayListenerFallback(port = DEFAULT_LOCAL_GATEWAY_PORT) {
    if (process.platform !== 'win32')
        return;
    const listenerPid = findListeningPidWindows(port);
    if (listenerPid == null)
        return;
    const img = getWindowsProcessImageName(listenerPid);
    if (img) {
        const lower = img.toLowerCase();
        if (lower !== 'node.exe' && lower !== 'node')
            return;
    }
    killPidTreeWindows(listenerPid);
}
/**
 * Stop autostart Gateway: recorded PID (full tree on Windows) + orphaned listener fallback.
 */
export function shutdownAutostartedGateway(port = DEFAULT_LOCAL_GATEWAY_PORT) {
    killPidRecordedInFile();
    killLocalGatewayListenerFallback(port);
}
/**
 * Same as {@link shutdownAutostartedGateway}, then verifies the TCP listener is gone (Windows).
 * Runs an extra kill round if something still owns the port — maximizes confidence on exit.
 */
export function shutdownAutostartedGatewayVerified(port = DEFAULT_LOCAL_GATEWAY_PORT) {
    const lines = [];
    shutdownAutostartedGateway(port);
    if (process.platform === 'win32') {
        let linger = findListeningPidWindows(port);
        if (linger !== null) {
            killPidTreeWindows(linger);
            linger = findListeningPidWindows(port);
        }
        if (linger !== null) {
            const img = getWindowsProcessImageName(linger);
            lines.push(`Warning: port ${port} still has a LISTENER (PID ${linger}${img ? ` — ${img}` : ''}). Another app may be using this port.`);
            return { portClear: false, lines };
        }
        lines.push(`Local Gateway (port ${port}): verified — no TCP listener.`);
        return { portClear: true, lines };
    }
    lines.push(`Local Gateway: stop sent (this OS does not auto-verify the port).`);
    return { portClear: true, lines };
}
/**
 * Stop a previously recorded autostart Gateway so npm can replace the global package tree.
 */
export function killRecordedLocalGateway() {
    killPidRecordedInFile();
}
//# sourceMappingURL=local-gateway-pid.js.map