#!/usr/bin/env python3
"""Diagnostic: timestamp every pipeline line relative to the edit."""
import os, re, 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")

env = dict(os.environ, RUST_LOG="info", 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 reader():
    for line in p.stdout:
        with lock:
            lines.append((time.monotonic(), line))
        sys.stdout.write(line)

threading.Thread(target=reader, daemon=True).start()

def wait_for(pred, timeout=30):
    end = time.monotonic() + timeout
    while time.monotonic() < end:
        with lock:
            for ts, line in reversed(lines):
                if pred(line):
                    return ts, line
        time.sleep(0.001)
    raise TimeoutError

wait_for(lambda l: "gen 1 hello" in l)
original = open(SOURCE).read()
try:
    for i in range(int(sys.argv[1]) if len(sys.argv) > 1 else 3):
        marker = f"diag-{i}-{time.time_ns()}"
        with open(SOURCE, "w") as h:
            h.write(original.replace("nested-v1", marker))
        t0 = time.monotonic()
        wait_for(lambda l, m=marker: f'"nested":"{m}"' in l)
        with lock:
            snapshot = list(lines)
        print(f"\n===== iteration {i} e2e={(time.monotonic()-t0)*1000:.1f}ms")
        for ts, line in snapshot:
            if ts >= t0:
                print(f"  +{(ts-t0)*1000:7.2f}  {line.rstrip()[:120]}")
        time.sleep(0.15)
finally:
    open(SOURCE, "w").write(original)
    time.sleep(0.4)
    try:
        p.stdin.write("q\n"); p.stdin.flush()
    except BrokenPipeError:
        pass
    try:
        p.wait(timeout=5)
    except subprocess.TimeoutExpired:
        p.kill()
