#!/usr/bin/env python3
"""Export current CAM and compare geometry to the A20 baseline."""
import csv
import difflib
import json
import re
from prepare_candidates import ROOT, BASE, SPECS, run, sha

def gerber_geometry(p):
    lines=p.read_text().splitlines()
    # Net-name attributes, source-file identity and timestamps are expected
    # metadata changes. Keep every aperture, coordinate and plot command.
    return '\n'.join(x for x in lines if not x.startswith(('%TF.CreationDate,','%TF.ProjectId,','%TO.N,','G04 Created by KiCad')))

def drill_geometry(p):
    return '\n'.join(x for x in p.read_text().splitlines() if not x.startswith(('; #@! TF.CreationDate,','; DRILL file KiCad')))

def positions(p):
    with p.open(newline='') as f:
        rows=list(csv.DictReader(f))
    return {r['Ref']: {k:v for k,v in r.items() if k!='Package'} for r in rows}

def main():
    report={}
    for key,(_,_,name) in SPECS.items():
        dst=ROOT/key; pcb=dst/(name+'.kicad_pcb')
        ger=dst/'gerbers'; drill=dst/'drill'; pos=dst/'centroid-front.csv'
        ger.mkdir(exist_ok=True); drill.mkdir(exist_ok=True)
        for generated in drill.iterdir():
            if generated.is_file(): generated.unlink()
        assert run(['pcb','export','gerbers','--board-plot-params','--output',str(ger)+'/',str(pcb)],dst/'gerber-export.log')==0
        assert run(['pcb','export','drill','--format','excellon','--excellon-separate-th','--generate-map','--map-format','svg','--generate-report','--report-path',str(drill/'drill-report.txt'),'--output',str(drill)+'/',str(pcb)],dst/'drill-export.log')==0
        assert run(['pcb','export','pos','--format','csv','--units','mm','--side','front','--smd-only','--exclude-dnp','--output',str(pos),str(pcb)],dst/'centroid-export.log')==0
        old=BASE/'engineering_handoff_local/three_board_cli_refresh_A20'/key
        def layer(p): return p.name.split('-',1)[1]
        oldger={layer(p):p for p in (old/'gerbers').glob('*.gbr')}
        newger={layer(p):p for p in ger.glob('*.gbr')}
        assert set(oldger)==set(newger),(oldger.keys(),newger.keys())
        matches={}
        for layer_name in oldger:
            a=gerber_geometry(oldger[layer_name]);b=gerber_geometry(newger[layer_name])
            if a!=b:
                (dst/('cam-diff-'+layer_name+'.txt')).write_text('\n'.join(difflib.unified_diff(a.splitlines(),b.splitlines())))
            matches[layer_name]=a==b
        assert all(matches.values()),matches
        olddr={layer(p):p for p in (old/'drill').glob('*.drl')}
        newdr={layer(p):p for p in drill.glob('*.drl')}
        assert set(olddr)==set(newdr)
        drill_matches={n:drill_geometry(olddr[n])==drill_geometry(newdr[n]) for n in olddr}
        assert all(drill_matches.values()),drill_matches
        a=positions(old/'centroid-front.csv');b=positions(pos)
        assert a==b,(a,b)
        report[key]={'candidate_board_sha256':sha(pcb),'gerber_geometry_match':matches,'drill_geometry_match':drill_matches,'position_records_unchanged':len(b),'scope':'Geometry, aperture and command equality after excluding generation identity/timestamps and net name attributes. Package column may become library-qualified; numerical position and other fields identical.'}
    (ROOT/'cam_comparison.json').write_text(json.dumps(report,indent=2)+'\n')
    print(json.dumps(report,indent=2))

if __name__=='__main__': main()
