import adsk.core, adsk.fusion, json, pathlib, traceback
OUT=pathlib.Path(C28_ROOT)
app=adsk.core.Application.get();d=adsk.fusion.Design.cast(app.activeProduct);root=d.rootComponent;ex=d.exportManager
for folder in ['cad/parts','meshes/parts','drawings']:(OUT/folder).mkdir(parents=True,exist_ok=True)
log=[]
def note(s):
    log.append(s);(OUT/'audit/export_progress.json').write_text(json.dumps(log,indent=2))
def occ(term):return next(o for o in root.allOccurrences if term in o.component.name)
def bbox(b):
    q=b.boundingBox
    return [v*10 for v in [q.minPoint.x,q.maxPoint.x,q.minPoint.y,q.maxPoint.y,q.minPoint.z,q.maxPoint.z]]
try:
    c=occ('C28_R1_16_').component
    if c.features.filletFeatures.count==0:
        ed=adsk.core.ObjectCollection.create()
        for e in c.bRepBodies.item(0).edges:
            bb=e.boundingBox
            if abs(bb.minPoint.x+4.19)<1e-5 and abs(bb.maxPoint.x+4.19)<1e-5:ed.add(e)
        fi=c.features.filletFeatures.createInput();fi.edgeSetInputs.addConstantRadiusEdgeSet(ed,adsk.core.ValueInput.createByString('0.6 mm'),True)
        c.features.filletFeatures.add(fi).name='Smooth PTT exposed-edge radius 0.6 mm'
        note('PTT outer edge fillet 0.6 mm')
    c=occ('C28_R1_10_').component
    if c.sketches.count==0:
        cp=c.constructionPlanes.createInput();cp.setByOffset(c.xYConstructionPlane,adsk.core.ValueInput.createByString('0.51 mm'))
        plane=c.constructionPlanes.add(cp);plane.name='Laser mark base / 0.04 mm depth'
        s=c.sketches.add(plane);s.name='Play symbol laser outline'
        def poly(coords):
            for a,b in zip(coords,coords[1:]+coords[:1]):s.sketchCurves.sketchLines.addByTwoPoints(adsk.core.Point3D.create(a[0]/10,a[1]/10,0),adsk.core.Point3D.create(b[0]/10,b[1]/10,0))
        poly([(-3.3,-52),(5,-47),(-3.3,-42)])
        poly([(-3,-51.469),(4.42,-47),(-3,-42.531)])
        profile=min(s.profiles,key=lambda p:p.areaProperties().area)
        ei=c.features.extrudeFeatures.createInput(profile,adsk.fusion.FeatureOperations.CutFeatureOperation)
        ei.setDistanceExtent(False,adsk.core.ValueInput.createByString('0.10 mm'))
        c.features.extrudeFeatures.add(ei).name='Play symbol shallow laser mark 0.04 mm'
        s.saveAsDXF(str(OUT/'drawings/C28_R1_Play_Symbol_Laser_Artwork.dxf'))
        s.isVisible=False;plane.isLightBulbOn=False
        note('Play symbol engraved and native DXF exported')
    d.timeline.moveToEnd()
    # All source instances and their world-coordinate properties are retained in this audit.
    inventory=[]
    for o in root.allOccurrences:
        if not o.component.bRepBodies.count:continue
        inventory.append({'name':o.component.name,'transform':o.transform2.asArray(),'bodies':[{'name':b.name,'volume_mm3':b.volume*1000,'bbox_mm':bbox(b),'isSolid':b.isSolid,'faces':b.faces.count} for b in o.bRepBodies]})
    (OUT/'audit/Concept_28_R1_Fusion_manifest.json').write_text(json.dumps({'application':'Autodesk Fusion','version':app.version,'baseline':'Final Concept 27 R2 with Fusion casting-release adaptation','components':inventory},indent=2))
    exp=ex.createFusionArchiveExportOptions(str(OUT/'cad/Walkie_One_28_R1_Chalk_Ember.f3d'));assert ex.execute(exp)
    note('Native F3D archive saved')
    step=ex.createSTEPExportOptions(str(OUT/'cad/Walkie_One_28_R1_REFERENCE_ASSEMBLY.step'));step.isIncludingInvisibleBodies=True;step.isIncludingInvisibleComponents=True;assert ex.execute(step)
    note('Full reference STEP saved')
    for o in root.allOccurrences:
        c=o.component
        if not c.bRepBodies.count or '_REF_' in c.name:continue
        if globals().get('C28_REUSE_STOCK_MESH',False) and 'Woven_Mesh_REFERENCE_RODS' in c.name:
            note('Unchanged purchased mesh uses its previously verified STEP/STL exports')
            continue
        step=ex.createSTEPExportOptions(str(OUT/'cad/parts'/f'{c.name}.step'));step.geometry=o;assert ex.execute(step)
        stl=ex.createSTLExportOptions(o,str(OUT/'meshes/parts'/f'{c.name}.stl'));stl.meshRefinement=adsk.fusion.MeshRefinementSettings.MeshRefinementHigh;assert ex.execute(stl)
        note('Part export '+c.name)
    # Exclude only OEM electronics from the case/fastener assembly export.
    hidden=[]
    for o in root.allOccurrences:
        if o.component.bRepBodies.count and ('_REF_' in o.component.name):
            hidden.append(o);o.isLightBulbOn=False
    step=ex.createSTEPExportOptions(str(OUT/'cad/Walkie_One_28_R1_CASE.step'));step.isIncludingInvisibleComponents=False;step.isIncludingInvisibleBodies=False;assert ex.execute(step)
    for o in hidden:o.isLightBulbOn=True
    note('Case STEP saved; OEM visibility restored')
    # Camera uses actual CAD geometry; no generative image or substituted surfaces.
    cam=app.activeViewport.camera;cam.isSmoothTransition=False;cam.cameraType=adsk.core.CameraTypes.OrthographicCameraType
    cam.eye=adsk.core.Point3D.create(-15,6,32);cam.target=adsk.core.Point3D.create(0,0,-1.2);cam.upVector=adsk.core.Vector3D.create(0,1,0);cam.isFitView=True;app.activeViewport.camera=cam
    app.activeViewport.saveAsImageFile(str(OUT/'renders/Fusion_28_Assembly.png'),1800,1800)
    note('Finished Fusion export pass')
    print('Native F3D, reference STEP, case STEP, individual STEP/STL and laser artwork exported.')
except:
    (OUT/'audit/export_error.txt').write_text(traceback.format_exc());print(traceback.format_exc())
