"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.sleepMs = sleepMs;
exports.buildWindowsTaskkillArgs = buildWindowsTaskkillArgs;
exports.bestEffortKillWindowsProcessTree = bestEffortKillWindowsProcessTree;
exports.bestEffortKillPid = bestEffortKillPid;
const node_child_process_1 = require("node:child_process");
const node_util_1 = require("node:util");
const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
function sleepMs(milliseconds) {
    return new Promise((resolve) => setTimeout(resolve, milliseconds));
}
function buildWindowsTaskkillArgs(pid, force) {
    assertValidPid(pid);
    return force ? ['/PID', String(pid), '/T', '/F'] : ['/PID', String(pid), '/T'];
}
function assertValidPid(pid) {
    if (!Number.isInteger(pid) || pid <= 0) {
        throw new Error(`Invalid process pid: ${String(pid)}`);
    }
}
async function bestEffortTaskkill(pid, force) {
    try {
        await execFileAsync('taskkill.exe', buildWindowsTaskkillArgs(pid, force), {
            windowsHide: true,
            maxBuffer: 1024 * 1024,
        });
    }
    catch {
        // Best effort only.
    }
}
async function bestEffortListWindowsDescendantPids(pid) {
    assertValidPid(pid);
    try {
        const command = `
$processes = Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId
$frontier = @(${String(pid)})
$result = @()
while ($frontier.Count -gt 0) {
  $next = @()
  foreach ($parentPid in $frontier) {
    foreach ($child in $processes | Where-Object { $_.ParentProcessId -eq $parentPid }) {
      $childPid = [int]$child.ProcessId
      $result += $childPid
      $next += $childPid
    }
  }
  $frontier = $next
}
$result | ForEach-Object { [Console]::Out.WriteLine($_) }
`;
        const { stdout } = await execFileAsync('powershell.exe', ['-NoProfile', '-Command', command], {
            windowsHide: true,
            maxBuffer: 1024 * 1024,
        });
        const parsed = [];
        for (const line of stdout.split(/\r?\n/)) {
            const trimmed = line.trim();
            if (trimmed === '') {
                continue;
            }
            const parsedPid = Number(trimmed);
            if (Number.isInteger(parsedPid) && parsedPid > 0) {
                parsed.push(parsedPid);
            }
        }
        return parsed;
    }
    catch {
        return [];
    }
}
async function bestEffortKillWindowsProcessTree(pid) {
    assertValidPid(pid);
    const descendantPids = await bestEffortListWindowsDescendantPids(pid);
    for (const descendantPid of descendantPids.slice().reverse()) {
        await bestEffortTaskkill(descendantPid, false);
    }
    await bestEffortTaskkill(pid, false);
    await sleepMs(1_000);
    for (const descendantPid of descendantPids.slice().reverse()) {
        await bestEffortTaskkill(descendantPid, true);
        bestEffortKillPid(descendantPid);
    }
    await bestEffortTaskkill(pid, true);
    bestEffortKillPid(pid);
}
function bestEffortKillPid(pid) {
    assertValidPid(pid);
    try {
        process.kill(pid, 'SIGKILL');
    }
    catch {
        // Best effort only.
    }
}
