import json, os, shutil, subprocess, time, glob, threading
ROOT="/Users/oscar/.worktree/hot-reload/labs/hot-reload"; REC=f"{ROOT}/target/kan-hot/debug/rustc"
SRC=f"{ROOT}/api-common/src/lib.rs"; BASE="/private/var/folders/ft/fkt3bwqd01g7f54wvyz9wgjc0000gn/T/opencode/pipe/out30"
def load(n): return json.load(open(f"{REC}/{n}.json"))
def strip_owned(argv):
    out=[]; i=1
    while i<len(argv):
        a=argv[i]
        if a=="-C" and i+1<len(argv) and any(argv[i+1].startswith(p) for p in ("incremental=","codegen-units=","debuginfo=")): i+=2; continue
        if a.startswith("-C") and any(a[2:].startswith(p) for p in ("incremental=","codegen-units=","debuginfo=")): i+=1; continue
        out.append(a); i+=1
    return out
def rewrite_extern(argv,name,path):
    out=[]; i=0
    while i<len(argv):
        a=argv[i]
        if a=="--extern" and i+1<len(argv) and argv[i+1].startswith(name+"="):
            out+=["--extern",f"{name}={path}"]; i+=2; continue
        if a.startswith(f"--extern={name}="):
            out.append(f"--extern={name}={path}"); i+=1; continue
        out.append(a); i+=1
    return out
common=load("api_common"); api=load("api"); orig=open(SRC).read(); assert "nested-v1" in orig
shutil.rmtree(BASE,ignore_errors=True); os.makedirs(BASE)
def run(mode,mark,i):
    d=f"{BASE}/{mode}"; os.makedirs(d,exist_ok=True)
    open(SRC,"w").write(orig.replace("nested-v1",mark))
    ca=[common["argv"][0]]+strip_owned(common["argv"])+["-C","debuginfo=0","-C","codegen-units=1"]
    j=ca.index("--out-dir"); ca[j+1]=d
    env=dict(common["env"]); env["RUSTC_BOOTSTRAP"]="1"
    if mode=="mir": ca+=["-Zalways-encode-mir"]
    t0=time.monotonic()
    p=subprocess.Popen(ca,cwd=common["cwd"],env=env,stdout=subprocess.PIPE,stderr=subprocess.STDOUT,text=True,bufsize=1)
    state={"tmeta":None,"tdone":None}
    def reader():
        for line in p.stdout:
            if state["tmeta"] is None and '"emit":"metadata"' in line:
                state["tmeta"]=time.monotonic()-t0
        state["tdone"]=time.monotonic()-t0
    th=threading.Thread(target=reader,daemon=True); th.start()
    while state["tmeta"] is None and state["tdone"] is None:
        time.sleep(0.0003)
    ares=None; mok=False
    if state["tmeta"] is not None:
        src=os.path.join(d,[f for f in os.listdir(d) if f.endswith(".rmeta")][0])
        md=f"{BASE}/meta-{mode}-{i}"; os.makedirs(md,exist_ok=True)
        rmeta=os.path.join(md,os.path.basename(src)); shutil.copy(src,rmeta)
        aa=rewrite_extern([api["argv"][0]]+strip_owned(api["argv"]),"api_common",rmeta)
        aa+=["-C","debuginfo=0","-C","codegen-units=8","-C",f"incremental={BASE}/inc/{mode}"]
        j=aa.index("--out-dir"); aa[j+1]=d
        ta=time.monotonic(); pa=subprocess.run(aa,cwd=api["cwd"],env=env,stdout=subprocess.DEVNULL,stderr=subprocess.PIPE); ares=((time.monotonic()-ta)*1000,pa.returncode,pa.stderr)
    th.join(); p.wait()
    mok=any(mark.encode() in open(f,"rb").read() for f in glob.glob(os.path.join(d,"libapi-*.rlib")))
    return state["tmeta"],state["tdone"],ares,mok
try:
    for mode in ["nof","mir"]:
        print("=====",mode)
        for i in range(3):
            tm,td,ares,mok=run(mode,f"e30-{mode}-{i}",i)
            errs=[]
            if ares:
                errs=[l[:200] for l in ares[2].decode(errors="replace").splitlines() if '"level":"error"' in l][:1]
            print(f" {i}: meta@{tm and round(tm*1000,1)} done@{td*1000:.1f} api={ares and (round(ares[0],1),ares[1])} marker={mok} errs={errs}")
            time.sleep(.15)
finally:
    open(SRC,"w").write(orig)
