from pathlib import Path
import sys,shutil,re,json
R=Path(__file__).resolve().parent;B=R.parent;sys.path.insert(0,str(B/'parity_metadata_closure_A22'))
from prepare_candidates import forms,run,sha
from align_and_verify import footprint_rows,netlist,semantic_geometry
D=R/'paired';D.mkdir(exist_ok=True);N='lamp_safety_evt_a1_metadata';S=R/'baseline'
for ext in ['kicad_pcb','kicad_pro','kicad_sch']:shutil.copy2(S/('lamp_safety_evt_a0.'+ext),D/(N+'.'+ext))
s=(D/(N+'.kicad_sch')).read_text().replace('(project "lamp_safety_evt_a0"','(project "'+N+'"');(D/(N+'.kicad_sch')).write_text(s)
for n in ['Project.kicad_sym','sym-lib-table']:shutil.copy2(S/n,D/n)
run(['sch','export','netlist','--format','kicadxml','--output',str(D/'netlist.xml'),str(D/(N+'.kicad_sch'))],D/'netlist.log')
fps,pins=netlist(D/'netlist.xml');p=D/(N+'.kicad_pcb');before=p.read_text();names={v.lstrip('/'):v for v in pins.values() if not v.startswith('unconnected-')}
aligned=re.sub(r'\(net\s+"([^"]+)"\s*\)',lambda m:'(net '+json.dumps(names[m.group(1).lstrip('/')])+')',before)
seen=set()
for st,en,f,ref,ident in reversed(list(footprint_rows(aligned))):
 assert fps[ref].rsplit(':',1)[-1]==ident.rsplit(':',1)[-1]
 u=f
 for ps,pe,pad in reversed(list(forms(u,'pad'))):
  pin=re.match(r'\(pad\s+"([^"]*)"',pad).group(1);key=(ref,pin);assert key in pins;seen.add(key)
  target=pins[key];old=re.search(r'\(net\s+"([^"]+)"',pad)
  if target.startswith('unconnected-'):
   assert not old;new=pad[:-1]+'(net '+json.dumps(target.replace('/','{slash}'))+'))';u=u[:ps]+new+u[pe:]
  else:assert old and old.group(1)==target,(key,target)
 u=re.sub(r'^(\(footprint\s+)"[^"]+"',lambda m:m.group(1)+json.dumps(fps[ref]),u,count=1)
 aligned=aligned[:st]+u+aligned[en:]
assert seen==set(pins),(set(pins)-seen)
assert semantic_geometry(aligned)==semantic_geometry(before)
p.write_text(aligned)
run(['sch','erc','--severity-all','--format','json','--output',str(D/'erc.json'),str(D/(N+'.kicad_sch'))],D/'erc.log')
run(['pcb','drc','--severity-all','--all-track-errors','--schematic-parity','--refill-zones','--save-board','--format','json','--output',str(D/'drc.json'),str(p)],D/'drc.log')
j=json.loads((D/'drc.json').read_text());assert not j['violations'] and not j['unconnected_items'] and not j['schematic_parity'],j
E=json.loads((D/'erc.json').read_text());assert not [v for sh in E['sheets'] for v in sh.get('violations',[])]
(R/'metadata_checks.json').write_text(json.dumps({'geometry_tokens_unchanged_before_native_save':True,'matched_pin_net_pairs':len(pins),'erc_findings':0,'drc_findings':0,'unconnected_items':0,'schematic_parity_findings':0,'baseline_parity_findings':154,'candidate_board_sha256':sha(p),'manufacturing_status':'FABRICATION_HOLD','IR_connected':False},indent=2)+'\n')
print((R/'metadata_checks.json').read_text())
