import ctypes, json, msvcrt, subprocess, time, psutil
from ctypes import wintypes
k = ctypes.WinDLL('kernel32', use_last_error=True)
k.PeekNamedPipe.argtypes = [wintypes.HANDLE, ctypes.c_void_p, wintypes.DWORD, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
k.PeekNamedPipe.restype = wintypes.BOOL

def eof(stream):
    ok = k.PeekNamedPipe(msvcrt.get_osfhandle(stream.fileno()), None, 0, None, None, None)
    error = ctypes.get_last_error() if not ok else 0
    assert ok or error == 109, error
    return error == 109

def identity(p):
    return {'pid': p.pid, 'created': p.create_time(), 'exe': p.exe()}

def run(mode):
    command = 'set /p hold= & rem agent7-psyche' if mode == 'builtin' else 'ping -n 30 127.0.0.1 >NUL & rem agent7-psyche'
    flags = 4 if mode == 'suspended' else 0
    child = subprocess.Popen(['cmd', '/D', '/Q', '/C', command], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, creationflags=flags)
    root = psutil.Process(child.pid)
    result = {'mode':mode, 'root':identity(root), 'cmdline':root.cmdline()}
    assert 'agent7-psyche' in ' '.join(result['cmdline'])
    descendant = None
    deadline = time.monotonic() + (1 if mode == 'builtin' else 5)
    try:
        if mode != 'suspended':
            while time.monotonic() < deadline:
                children = root.children(recursive=True)
                if children:
                    descendant = children[0]
                    break
                time.sleep(.005)
            assert (descendant is not None) == (mode == 'legacy'), mode
        result['descendant'] = identity(descendant) if descendant else None
    finally:
        child.kill()
        result['root_exit'] = child.wait(timeout=2)
    deadline = time.monotonic() + .5
    while time.monotonic() < deadline and not eof(child.stderr):
        time.sleep(.005)
    result['stderr_eof'] = eof(child.stderr)
    result['stdout_eof'] = eof(child.stdout)
    result['descendant_alive_after_root_exit'] = descendant.is_running() if descendant else False
    print(json.dumps(result), flush=True)
    child.stdin.close(); child.stdout.close(); child.stderr.close()
    assert result['stderr_eof'] == (mode != 'legacy'), result
    if descendant:
        assert result['descendant_alive_after_root_exit']

for mode in ('suspended', 'legacy', 'builtin'):
    run(mode)
