"""New card version with measured part axes + aim limits (and an optional re-pivoted GLB) for a vehicle.
usage: python3 tools/vehicles/add_axes.py <slug> [--repivot]   (10 Oct 2026: helicopter tail rotor orbiting, guns through the hull)
nodes.axes  = {Node: [x,y,z]} local turning axis (guns: {yaw, pitch}); horizontal surfaces have +X, rudders +Y, gun pitch is
              [-1,0,0] so a POSITIVE angle raises the barrel; positive surface angle = trailing edge up.
nodes.limits = {Node: [min, max]} or guns {yaw: [..], pitch: [..]} in radians; spinning parts have none."""
import copy, glob, hashlib, json, os, shutil, subprocess, sys, time
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.insert(0, os.path.join(ROOT, 'lib'))
import glb, card as cardlib  # noqa: E402


def node(*a):
    return subprocess.run(['node', *a], capture_output=True, text=True, check=True, cwd=ROOT).stdout


def main(slug, repivot=False):
    allc = cardlib.load_all(ROOT)
    cid = next(k for k in allc if k.endswith('/' + slug))
    cur = allc[cid][-1]
    src = f"{ROOT}/store/blobs/{cur['files']['glb'].split(':')[1]}.glb"
    m = json.loads(node('tools/pack/part_axes.mjs', src))
    f = src
    if repivot:
        f = f'/tmp/{slug}-repivot.glb'
        node('tools/pack/repivot.mjs', src, f, json.dumps(m['pivots']))
        m = json.loads(node('tools/pack/part_axes.mjs', f))
    fam = cid.split('/')[0].split('.')[1]
    heli = fam == 'rotor'
    axes, limits = {}, {}
    for n, a in m['axes'].items():
        if isinstance(a, dict):  # guns
            axes[n] = {'yaw': [0, 1, 0], 'pitch': [-1, 0, 0]}
            limits[n] = ({'yaw': [-1.1, 1.1], 'pitch': [-0.9, 0.15]} if heli else
                         {'yaw': [0, 0], 'pitch': [-0.12, 0.35]} if n == 'Gun' else
                         {'yaw': [-1.0, 1.0] if 'humvee' not in slug else [0, 0], 'pitch': [-0.15, 0.6]})
            continue
        if n.startswith('Rudder'):
            a = a if a[1] >= 0 else [-x for x in a]; limits[n] = [-0.4, 0.4]
        elif n.startswith(('Aileron', 'Elevon', 'Elevator', 'Stabilator', 'Canard', 'Flap', 'DragRudder')):
            a = a if a[0] >= 0 else [-x for x in a]
            limits[n] = ([-0.6, 0] if n.startswith('Flap') else [-0.45, 0] if n.startswith('DragRudderLower') else
                         [0, 0.45] if n.startswith('DragRudder') else [-0.35, 0.35])
        elif n == 'Turret':
            pass  # turns all the way round
        axes[n] = [round(x, 4) for x in a]
    c = copy.deepcopy(cur)
    c['version'] = cur['version'] + 1
    c['nodes'] = {**cur['nodes'], 'axes': axes, 'limits': limits}
    fix = 'measured part axes + aim limits (10 Oct 2026 pivot audit)'
    if repivot:
        h = hashlib.sha256(open(f, 'rb').read()).hexdigest()
        shutil.copyfile(f, f'{ROOT}/store/blobs/{h}.glb')
        r = glb.measure(f)
        c['files'] = {**cur['files'], 'glb': f'sha256:{h}'}
        c['render'] = {**cur['render'], 'bytes': r['bytes'], 'tris': r['tris']}
        fix = 'pivots moved to the rotor hubs and the gun turret (they sat on the ground origin: the tail rotor orbited the aircraft); ' + fix
    c['provenance'] = {**cur['provenance'], 'fix': fix, 'fixed': time.strftime('%Y-%m-%d')}
    c['status'] = 'approved'
    c['release'] = cardlib.release_hash(c)
    print(cardlib.write(ROOT, c), len(axes), 'axes', len(limits), 'limits')


if __name__ == '__main__':
    main(sys.argv[1], '--repivot' in sys.argv)
