"""One-shot bootstrap after the GLBs arrive from the Mac: extract meshes, apply substitutions
(no fillet_holder/yoke_exact sources on this host — use drilled holder / filleted yoke), then run the
gripper pipeline + arm pipeline + composer. Run on puget in the mount: ~/cad_venv/bin/python bootstrap_build.py"""
import shutil
import subprocess
import sys

PY = sys.executable

def step(name, fn):
    print(f"\n=== {name} ===")
    try:
        fn()
        return True
    except Exception as e:
        print(f"FAILED: {type(e).__name__}: {e}")
        return False

def run(script):
    r = subprocess.run([PY, script], capture_output=True, text=True)
    print(r.stdout[-2000:])
    if r.returncode != 0:
        raise RuntimeError(r.stderr.strip().splitlines()[-1] if r.stderr.strip() else f"{script} rc={r.returncode}")

# 1. seed working copies + extract meshes from the Mac GLBs
step("seed GLBs", lambda: (shutil.copy("gripper.glb", "gripper_from_blender.glb"),
                           shutil.copy("two_servo.glb", "two_servo_from_blender.glb")))
step("extract meshes from gripper.glb", lambda: run("extract_meshes_from_glb.py"))
# 2. substitutions (sources for the filleted/exact parts live only on the lab)
step("substitutions", lambda: (shutil.copy("holder_approx_drilled.stl", "holder_fillet.stl"),
                               shutil.copy("yoke_fillet.stl", "yoke_exact.stl")))
# 3. gripper pipeline
ok_g = step("gripper: beautify", lambda: run("gen_gripper_beautify.py")) \
   and step("gripper: connect", lambda: run("gen_gripper_connect.py")) \
   and step("gripper: urdf", lambda: run("gen_gripper_urdf.py")) \
   and step("gripper: polish", lambda: run("gen_gripper_polish.py"))
# 4. arm pipeline (first exercise of the RECONSTRUCTED read_layout)
ok_a = step("arm: beauty", lambda: run("gen_beauty.py")) \
   and step("arm: detach", lambda: run("gen_detach.py"))
# 5. composer
if ok_g and ok_a:
    step("compose arm+gripper", lambda: run("gen_arm_gripper.py"))
print(f"\nRESULT: gripper={'OK' if ok_g else 'FAIL'} arm={'OK' if ok_a else 'FAIL'}")
