import { logInfo, logWarn } from './logger-context.js';
export const DEBUG_HANG = process.env.MCPORTER_DEBUG_HANG === '1';
function describeHandle(handle) {
    if (!handle || (typeof handle !== 'object' && typeof handle !== 'function')) {
        return String(handle);
    }
    const ctor = handle.constructor?.name ?? typeof handle;
    if (ctor === 'Socket') {
        try {
            const socket = handle;
            const parts = ['Socket'];
            if (socket.localAddress) {
                parts.push(`local=${socket.localAddress}:${socket.localPort ?? '?'}`);
            }
            if (socket.remoteAddress) {
                parts.push(`remote=${socket.remoteAddress}:${socket.remotePort ?? '?'}`);
            }
            if (typeof socket.address === 'function') {
                const addr = socket.address?.();
                if (addr) {
                    parts.push(`addr=${addr.address}:${addr.port}`);
                }
            }
            const host = handle._host;
            if (host) {
                parts.push(`host=${host}`);
            }
            const pipeName = handle.path;
            if (pipeName) {
                parts.push(`path=${pipeName}`);
            }
            const extraKeys = Reflect.ownKeys(handle)
                .filter((key) => typeof key === 'string' && key.startsWith('_') && !['_events', '_eventsCount'].includes(key))
                .slice(0, 4);
            if (extraKeys.length > 0) {
                parts.push(`keys=${extraKeys.join(',')}`);
            }
            return parts.join(' ');
        }
        catch {
            return ctor;
        }
    }
    if (typeof handle === 'object') {
        const pid = handle.pid;
        if (typeof pid === 'number') {
            return `${ctor} (pid=${pid})`;
        }
        const fd = handle.fd;
        if (typeof fd === 'number') {
            return `${ctor} (fd=${fd})`;
        }
    }
    return ctor;
}
export function dumpActiveHandles(label) {
    if (!DEBUG_HANG) {
        return;
    }
    const proc = process;
    const activeHandles = proc._getActiveHandles?.() ?? [];
    const activeRequests = proc._getActiveRequests?.() ?? [];
    logInfo(`[debug] ${label}: ${activeHandles.length} active handle(s), ${activeRequests.length} request(s)`);
    for (const handle of activeHandles) {
        logInfo(`[debug] handle => ${describeHandle(handle)}`);
    }
    for (const request of activeRequests) {
        logInfo(`[debug] request => ${describeHandle(request)}`);
    }
}
export function terminateChildProcesses(label) {
    const proc = process;
    const handles = proc._getActiveHandles?.() ?? [];
    for (const handle of handles) {
        if (!handle || typeof handle !== 'object') {
            continue;
        }
        const candidate = handle;
        const ctor = handle.constructor?.name ?? '';
        if (ctor === 'Socket' && typeof handle.destroy === 'function') {
            try {
                handle.destroy?.();
                if (typeof handle.unref === 'function') {
                    handle.unref?.();
                }
            }
            catch {
                // ignore
            }
        }
        if (typeof candidate.stdout?.destroy === 'function') {
            try {
                candidate.stdout.destroy?.();
            }
            catch {
                // ignore
            }
        }
        if (typeof candidate.stderr?.destroy === 'function') {
            try {
                candidate.stderr.destroy?.();
            }
            catch {
                // ignore
            }
        }
        if (typeof candidate.stdin?.end === 'function') {
            try {
                candidate.stdin.end?.();
            }
            catch {
                // ignore
            }
        }
        // When DEBUG_HANG is enabled we leave extra breadcrumbs so developers can see
        // which transports required forceful teardown before Node would exit.
        if (DEBUG_HANG) {
            const killed = candidate.kill?.('SIGKILL') ?? false;
            if (candidate.pid) {
                const outcome = killed ? 'killed' : 'kill-failed';
                logWarn(`[debug] forcibly ${outcome} child pid=${candidate.pid} (${label})`);
            }
        }
        else if (typeof candidate.kill === 'function' && typeof candidate.pid === 'number' && !candidate.killed) {
            try {
                candidate.kill('SIGKILL');
            }
            catch {
                // ignore
            }
        }
    }
}
//# sourceMappingURL=runtime-debug.js.map