"""Preserve the tscircuit GLB verbatim below a verified molecule-frame root.

tscircuit output is millimetres/Y-up; molecule imports are metres/Z-up.
Attachment positions come from the existing STEP/PCB-derived footprint contract.
No mesh, texture, material, or binary buffer is regenerated.
"""
import copy
import hashlib
import json
import struct
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]

def unpack(raw):
    magic, version, length = struct.unpack_from('<III', raw)
    assert magic == 0x46546c67 and version == 2 and length == len(raw)
    size, kind = struct.unpack_from('<II', raw, 12)
    assert kind == 0x4e4f534a
    return json.loads(raw[20:20 + size]), raw[20 + size:]

def anchor(board, stage):
    slug = stage.name
    source = board / 'dist/lib/index/3d.glb'
    raw = source.read_bytes()
    original, binary = unpack(raw)
    model = copy.deepcopy(original)
    fp = json.loads((stage / f'{slug}_footprint.json').read_text())
    assert model.get('textures') and model.get('images'), 'Missing detailed board textures'
    assert len(model['scenes']) == 1, 'Review nonstandard scene hierarchy'
    nodes = {n.get('name'): n for n in model['nodes']}
    origin = nodes['MP1']['translation']
    reference = next(p for p in fp['machinePins'] if p['name'] == 'MP1')
    assert reference['position'] == {'x': 0, 'y': 0}
    # Proper rotation (-x, z, y), positive determinant; millimetres to metres.
    offset = [origin[0], -origin[2], reference['z'] - origin[1]]
    positions = {}
    for pin in fp['machinePins'] + fp['contacts']:
        node = nodes[pin['name']]
        assert 'matrix' not in node
        x, y, z = node['translation']
        actual = [-x + offset[0], z + offset[1], y + offset[2]]
        expected = [pin['position']['x'], pin['position']['y'], pin['z']]
        assert all(abs(a - b) < 1e-6 for a, b in zip(actual, expected)), (pin['name'], actual, expected)
        positions[pin['name']] = actual
    roots = model['scenes'][0]['nodes']
    assert all(model['nodes'].index(nodes[p]) in roots for p in positions)
    root = {'name': 'MoleculeFrame', 'children': roots,
            'matrix': [-.001, 0, 0, 0, 0, 0, .001, 0, 0, .001, 0, 0,
                       *(v / 1000 for v in offset), 1]}
    model['scenes'][0]['nodes'] = [len(model['nodes'])]
    model['nodes'].append(root)
    stamp = {'anchored': True, 'upAxis': 'z', 'flMarker': 'MP1',
             'pinSize': 'medium', 'footprint': True, 'contactZ': reference['z'],
             'texturesPreserved': True, 'source': 'tscircuit detailed GLB',
             'anchorReference': f'{slug}_footprint.json'}
    model['asset'].setdefault('extras', {})['adomMolecule'] = stamp
    encoded = json.dumps(model, separators=(',', ':')).encode()
    encoded += b' ' * (-len(encoded) % 4)
    result = struct.pack('<III', 0x46546c67, 2, 20 + len(encoded) + len(binary))
    result += struct.pack('<II', len(encoded), 0x4e4f534a) + encoded + binary
    check, check_binary = unpack(result)
    assert check_binary == binary
    for key in ['meshes', 'materials', 'textures', 'images', 'buffers', 'bufferViews', 'accessors']:
        assert check[key] == original[key], key
    destination = stage / f'{slug}.glb'
    destination.write_bytes(result)
    report = {'source': str(source.relative_to(ROOT)),
              'sourceSha256': hashlib.sha256(raw).hexdigest(),
              'publishedSha256': hashlib.sha256(result).hexdigest(),
              'binaryPayloadPreserved': True, 'attachmentPositionsMm': positions,
              'meshes': len(check['meshes']), 'textures': len(check['textures']),
              'materials': len(check['materials']), 'conversion': stamp}
    (stage / 'docs/model-quality.json').write_text(json.dumps(report, indent=2) + '\n')
    return stamp

if __name__ == '__main__':
    for stage in sorted((ROOT / 'wiki-molecules').iterdir()):
        anchor(ROOT / 'boards' / stage.name.removeprefix('molecule-'), stage)
        print(stage.name, 'textures preserved; all 9 attachment positions verified')
