#!/usr/bin/env python3
"""Diagnostic edit->serving timing with a 1 ms poll (removes the 5 ms
quantisation of the official harness). Not a substitute for bench_reload.py."""
import os, re, statistics, subprocess, sys, threading, time
ROOT="/Users/oscar/.worktree/hot-reload/labs/hot-reload"
CLI="/Users/oscar/.worktree/hot-reload/target/debug/kan-hot-dev"
SOURCE=os.path.join(ROOT,"api-common","src","lib.rs")
n=int(sys.argv[1]) if len(sys.argv)>1 else 6
env=dict(os.environ,RUST_LOG="error",KAN_HOT_TIMING="1",KAN_HOT_EXAMPLE_INTERVAL_MS="50")
p=subprocess.Popen([CLI,"run","--bin","server","--lib","api"],cwd=ROOT,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.STDOUT,env=env,text=True,bufsize=1)
lines=[]; lock=threading.Lock()
def rd():
    for l in p.stdout:
        with lock: lines.append((time.monotonic(),l))
threading.Thread(target=rd,daemon=True).start()
def wait(pred,to=30):
    d=time.monotonic()+to
    while time.monotonic()<d:
        with lock:
            for t,l in reversed(lines):
                if pred(l): return t
        time.sleep(0.0008)
    raise TimeoutError
wait(lambda l:"gen 1 hello" in l)
orig=open(SOURCE).read(); samples=[]; builds=[]; links=[]; loads=[]
try:
    for i in range(n):
        mark=f"fine-{os.getpid()}-{i}-{time.time_ns()}"
        open(SOURCE,"w").write(orig.replace("nested-v1",mark))
        t0=time.monotonic()
        wait(lambda l,m=mark: f'"nested":"{m}"' in l)
        samples.append((time.monotonic()-t0)*1000)
        with lock: recent=[l for _,l in lines[-30:]]
        for l in recent:
            for pat,dst in ((r"cargo hot build ([0-9.]+)(ms|s|µs)",builds),(r"thin link ([0-9.]+)(ms|s|µs)",links),(r"loaded generation \d+ in ([0-9.]+)(ms|s|µs)",loads)):
                m=re.search(pat,l)
                if m:
                    v=float(m.group(1)); u=m.group(2)
                    dst.append(v*(1e-6 if u=="µs" else 1e-3 if u=="ms" else 1))
        time.sleep(0.15)
finally:
    open(SOURCE,"w").write(orig); time.sleep(.4)
    try: p.stdin.write("q\n");p.stdin.flush();p.wait(timeout=10)
    except Exception: p.kill()
def rep(name,xs):
    xs=[x*1000 if name!="e2e" else x for x in xs]
    print(f"{name}: n={len(xs)} mean={statistics.mean(xs):.1f} median={statistics.median(xs):.1f} min={min(xs):.1f} max={max(xs):.1f}")
rep("e2e",samples); rep("build",builds); rep("link",links); rep("load",loads)
