"""v2 print set: fixed piece (holder+riser+plate+ENPIRE+finger cradle) + moving piece
(yoke+conn+ENPIRE+thumb cradle), with rounded bond pads where the cradles kiss their structures."""
import numpy as np, trimesh
from gen_curvy import _rrect, _stitch
import importlib, gen_umi_v2  # noqa - ensures gnodes fresh? no, just reuse files on disk

def prism_aa(lo, hi, r=4.0, N=12):
    L = hi - lo; k = int(np.argmax(L)); lat = [i for i in range(3) if i != k]
    e1, e2 = np.eye(3)[lat[0]], np.eye(3)[lat[1]]
    h1, h2 = L[lat[0]] / 2, L[lat[1]] / 2
    c = (lo + hi) / 2
    rings = []
    for i in range(N):
        t = i / (N - 1)
        q = _rrect(h1, h2, min(r, h1 - 0.4, h2 - 0.4))
        p = c.copy(); p[k] = lo[k] + L[k] * t
        rings.append(p + np.outer(q[:, 0], e1) + np.outer(q[:, 1], e2))
    return _stitch(rings)

def L(n): return trimesh.load(f"gnode_v2_{n}.stl", force="mesh")
def U(parts):
    m = trimesh.boolean.union(parts, engine="manifold")
    bodies = m.split(only_watertight=False)
    keep = [b for b in bodies if b.volume > 100.0]
    return keep[0] if len(keep) == 1 else trimesh.util.concatenate(keep)

fc, tc = L("finger_cradle"), L("thumb_cradle")
plate, yoke = L("fixed_plate"), L("yoke")
# bond pads: envelope spanning cradle bottom shell into the structure
flo, fhi = fc.bounds; plo, phi = plate.bounds
pad_f = prism_aa(np.array([max(flo[0], plo[0]) + 3, phi[1] - 6.0, max(flo[2], plo[2]) + 1]),
                 np.array([min(fhi[0], phi[0]) - 3, flo[1] + 7.0, min(fhi[2], phi[2]) - 1]))
tlo, thi = tc.bounds; ylo, yhi = yoke.bounds
pad_t = prism_aa(np.array([max(tlo[0], ylo[0]) + 3, yhi[1] - 5.0, max(tlo[2], ylo[2]) + 2]),
                 np.array([min(thi[0], yhi[0]) - 3, tlo[1] + 7.0, min(thi[2], yhi[2]) - 2]))
servo_hull = trimesh.PointCloud(trimesh.load("st3215.stl", force="mesh").vertices).convex_hull
for nm, p in [("pad_f", pad_f), ("pad_t", pad_t)]:
    pts, _ = trimesh.sample.sample_surface(p, 6000)
    pen = float(trimesh.proximity.ProximityQuery(servo_hull).signed_distance(pts).max())
    print(nm, "vs servo penetration mm:", round(max(0.0, pen), 2))

fixed = U([L("holder"), L("fixed_riser"), L("fixed_plate"), L("enpire_fixed"), L("handle_column")])   # handle replaces cradle (2026-07-10)
moving = U([yoke, L("yoke_conn"), L("enpire_moving"), tc, pad_t])
fixed.export("gripper_v2_print_fixed.stl")
moving.export("gripper_v2_print_moving.stl")
for n, m in [("fixed", fixed), ("moving", moving)]:
    bodies = len(m.split(only_watertight=False))
    warn = "  <-- WARNING disjoint!" if bodies > 1 else ""
    print(f"gripper_v2_print_{n}: wt={m.is_watertight} bodies={bodies} vol={m.volume/1000:.1f}cm3 bbox={[round(v) for v in m.extents]}mm{warn}")
