import os,subprocess,time,threading
ROOT="/Users/oscar/.worktree/hot-reload/labs/hot-reload"; CLI="/Users/oscar/.worktree/hot-reload/target/debug/kan-hot-dev"
API=os.path.join(ROOT,"api","src","lib.rs")
env=dict(os.environ,RUST_LOG="error",KAN_HOT_EXAMPLE_INTERVAL_MS="300")
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,after=0,to=40):
    d=time.monotonic()+to
    while time.monotonic()<d:
        with lock:
            for t,l in lines[after:]:
                if pred(l): return t,l
        time.sleep(.005)
    raise TimeoutError
api=open(API).read()
try:
    wait(lambda l:"gen 1 hello" in l)
    with lock: n=len(lines)
    # duplicate the hello route so the builder panics
    dup=api.replace('        .query("count",', '        .query("hello", |_state: &AppState, _: ()| async move { "duplicate".to_string() })\n        .query("count",')
    assert dup!=api
    open(API,"w").write(dup)
    t,l=wait(lambda l:"reload failed" in l or "panicked" in l, after=n, to=60)
    print("panic/reload-failure line:",l.strip()[:160])
    wait(lambda l:"the previous generation is still active" in l, after=n, to=10)
    print("previous-generation message observed")
    # old generation still serving
    t,l=wait(lambda l:"gen 1 hello" in l and '"nested":"nested-v1"' in l, after=n, to=20)
    print("old generation still serving:",l.strip()[:120])
finally:
    open(API,"w").write(api); time.sleep(1)
    try: p.stdin.write("q\n");p.stdin.flush();p.wait(timeout=15)
    except Exception: p.kill()
