"""Factory-illustrated channel and slots in an estimated rear support cradle.

Run after build_rear_power_support_reference.py. No fitted datum is introduced.
"""
from pathlib import Path
import copy,hashlib,json,math
import cadquery as cq
from front_wing_geometry import absolute_tessellation
ROOT=Path(__file__).resolve().parent
SOURCE='rear-power-support-reference';OUTPUT='rear-formed-cradle-reference'
NAME='rear_power_connected_folded_cradle_inclined_faces_and_tunnel_ears'
data=json.loads((ROOT/(SOURCE+'.json')).read_text())
assembly=cq.Assembly.importStep(str(ROOT/(SOURCE+'.step')))
native={n:o.obj for n,o in assembly.objects.items()if o.obj is not None}
old=native[NAME];new=old
S=2032/2.4;T=3.;R=6.;RISE=24.;Y=246.;Z=-.16*S;WIDTH=.40*S;DEPTH=.18*S
# Replace the flat edge strips by constant-gauge quarter-circle folds and
# upright lips. All original X/Z bounds and center-floor material stay.
for side in [-1,1]:
    edge=Z+side*DEPTH/2;center=edge-side*(R+T)
    strip_min=min(edge,center)
    new=new.cut(cq.Solid.makeBox(WIDTH+2,T+.001,R+T,(-WIDTH/2-1,Y-.001,strip_min)))
    def p(u,h):return cq.Vector(-WIDTH/2,Y+h,center+side*u)
    rt=R+T
    edges=[cq.Edge.makeThreePointArc(p(0,0),p(rt/math.sqrt(2),rt-rt/math.sqrt(2)),p(rt,rt)),
           cq.Edge.makeLine(p(rt,rt),p(rt,RISE)),cq.Edge.makeLine(p(rt,RISE),p(R,RISE)),
           cq.Edge.makeLine(p(R,RISE),p(R,rt)),
           cq.Edge.makeThreePointArc(p(R,rt),p(R/math.sqrt(2),rt-R/math.sqrt(2)),p(0,T)),
           cq.Edge.makeLine(p(0,T),p(0,0))]
    fold=cq.Solid.extrudeLinear(cq.Wire.assembleEdges(edges),[],cq.Vector(WIDTH,0,0))
    new=new.fuse(fold)
# Factory p72 draws elongated mount openings. Their selected 9x18mm outline
# follows the existing inclined tangent, centered on each retained axis line.
slots=[]
for side,label in [(1,'left'),(-1,'right')]:
    node=data['nodes'][label];q=cq.Vector(*node['cradle_face_axis_body_mm']);a=cq.Vector(*node['rubber_axis_outward'])
    tangent=cq.Vector(side,1,0).normalized()
    tool=cq.Workplane(cq.Plane(origin=q,xDir=tangent,normal=a)).slot2D(18.,9.).extrude(6,both=True).val()
    new=new.cut(tool)
    slots.append(dict(side=label,center_body_mm=list(q.toTuple()),axis=list(a.toTuple()),long_axis=list(tangent.toTuple()),width_mm=9.,length_mm=18.))
new=new.clean();assert new.isValid()and len(new.Solids())==1
limits=('Factory Parts-1977 PDF p72 illustrates upturned channel edges and elongated inclined mounting openings. '
        'It does not calibrate the cradle. Selected24mm lip height,6mm inside bend radius,3mm gauge and9x18mm slots are construction estimates. '
        'The two repeated channel edges are a reconstruction interpretation,not a surveyed CHA266 pressing. '
        'Existing outline bounds,base bearing plane,fixing centers,gearbox pad faces,rubbers,fasteners,crossmember and source transforms remain. '
        'No fitted identity,slot adjustment range,drilling map,hidden attachment,weld,loaded support,tool access,clearance or replacement/removal path is verified. '
        'The common engine/body frame and earlier static source contacts remain unresolved;no neighboring material is cut to force fit.')
revision=dict(factory_source='https://www.spridgets.de/downloads/Parts-1977.pdf#page=72',
              catalog_comparison='https://www.moss-europe.co.uk/content/files/pdfs/moss-europe-sprite-midget-catalogue-issue-25.pdf#page=191',
              factory_drawing_scope='Upturned channel edge and elongated mounting openings;not dimensions or fitted configuration.',
              owner_evidence_scope=data['owner_evidence_scope'],owner_dimensions_applied=False,
              selected_lip_height_mm=RISE,selected_inside_bend_radius_mm=R,selected_gauge_mm=T,
              slots=slots,retained_source_sha256={ext:hashlib.sha256((ROOT/(SOURCE+ext)).read_bytes()).hexdigest()for ext in ['.json','.step']},limits=limits)
out=cq.Assembly(name='rear_gearbox_support_formed_channel_comparison');result=copy.deepcopy(data)
for part in result['parts']:
    n=part['name'];shape=new if n==NAME else native[n]
    out.add(shape,name=n,color=cq.Color(*part['color']))
    if n==NAME:
        vs,ts=absolute_tessellation(shape,.08,.14)
        part['vertices']=[round(v,4)for p in vs for v in p.toTuple()];part['triangles']=[i for t in ts for i in t]
result['formed_cradle_revision']=revision
# The preceding contact list was a historical sample;the new stage is audited
# independently against current active neighbors by validate_rear_cradle.py.
result['historical_sampled_source_contacts_mm3']=result.pop('sampled_source_contacts_mm3',{})
result['limits']=data['limits']+' '+limits
out.export(str(ROOT/(OUTPUT+'.step')))
(ROOT/(OUTPUT+'.json')).write_text(json.dumps(result,separators=(',',':'))+'\n')
restored=cq.importers.importStep(str(ROOT/(OUTPUT+'.step'))).val()
assert restored.isValid()and all(s.Volume()>0 for s in restored.Solids())
print(json.dumps(dict(groups=len(result['parts']),solids=len(restored.Solids()),cradle_connected=len(new.Solids())==1,old_volume=old.Volume(),new_volume=new.Volume())))
