import sys,re,json,shutil,uuid,subprocess
from pathlib import Path
ROOT=Path(__file__).resolve().parent;BASE=ROOT.parent
sys.path.insert(0,str(BASE/'parity_metadata_closure_A22'))
from prepare_candidates import forms,sha,run
from align_and_verify import footprint_rows,netlist
SRC=BASE/'parity_metadata_closure_A22/vacuum';DST=ROOT/'vacuum_corrected';DST.mkdir(exist_ok=True)
OLD='vacuum_control_evt_a1_metadata';NEW='vacuum_control_evt_a2_pmos_pinfix'
for n in ['fp-lib-table','sym-lib-table','Project.kicad_sym']:
 shutil.copyfile(SRC/n,DST/n)
shutil.copytree(SRC/'Vacuum_Shunt.pretty',DST/'Vacuum_Shunt.pretty',dirs_exist_ok=True)
shutil.copyfile(SRC/(OLD+'.kicad_pro'),DST/(NEW+'.kicad_pro'))
def symbol_fix(s):
 for st,en,b in reversed(list(forms(s,'symbol'))):
  if not b.startswith('(symbol "Project:PMOS_AO4407A"') and not b.startswith('(symbol "PMOS_AO4407A"'):continue
  for ps,pe,p in reversed(list(forms(b,'pin'))):
   m=re.search(r'\(number "([1-4])"',p)
   if m:
    n={'1':'4','2':'1','3':'2','4':'3'}[m.group(1)]
    b=b[:ps]+p[:m.start()]+m.group(0).replace('"'+m.group(1)+'"','"'+n+'"')+p[m.end():]+b[pe:]
  s=s[:st]+b+s[en:]
 return s
s=symbol_fix((SRC/(OLD+'.kicad_sch')).read_text()).replace('(project "'+OLD+'"','(project "'+NEW+'"')
(DST/(NEW+'.kicad_sch')).write_text(s)
(DST/'Project.kicad_sym').write_text(symbol_fix((DST/'Project.kicad_sym').read_text()))
s=(SRC/(OLD+'.kicad_pcb')).read_text()
for st,en,b,ref,_ in reversed(list(footprint_rows(s))):
 if ref not in ['Q1','Q3']:continue
 for ps,pe,p in reversed(list(forms(b,'pad'))):
  pin=re.match(r'\(pad "([^"]+)"',p).group(1)
  if pin in ['1','4']:
   target=('/VBUS_RAW' if ref=='Q1' else '/VBUS_SW') if pin=='1' else ('/PMOS_GATE' if ref=='Q1' else '/FAN_FET_GATE')
   p=re.sub(r'\(net "[^"]+"\)',lambda m:'(net '+json.dumps(target)+')',p)
   b=b[:ps]+p+b[pe:]
 s=s[:st]+b+s[en:]
# Remove old source-to-gate-pad straps and old gate fanouts. Rebuild only local routes.
removed=[]
for st,en,b in reversed(list(forms(s,'segment'))):
 points=re.findall(r'\((?:start|end) ([\d.-]+) ([\d.-]+)\)',b)
 if any(tuple(map(float,p)) in [(91.525,18.095),(91.525,21.905),(45.525,41.095),(45.525,44.905)] for p in points) or ('90.1981 18.7642' in b and '"F.Cu"' in b):
  removed.append(b);s=s[:st]+s[en:]
for st,en,b in reversed(list(forms(s,'via'))):
 if '(at 90.1981 18.7642)' in b or '(at 47.4045 41.095)' in b:
  s=s[:st]+s[en:]
def seg(a,b,net,layer='F.Cu',w=.2):
 return '\n(segment (start %s %s) (end %s %s) (width %s) (layer "%s") (net "%s") (uuid "%s"))'%(*a,*b,w,layer,net,uuid.uuid4())
def via(p,net):return '\n(via (at %s %s) (size 0.6) (drill 0.3) (layers "F.Cu" "B.Cu") (net "%s") (uuid "%s"))'%(*p,net,uuid.uuid4())
add=[]
add += [seg((91.525,18.095),(91.525,19.365),'/VBUS_RAW',w=.6),seg((45.525,41.095),(45.525,42.365),'/VBUS_SW',w=.6)]
# Keep the existing VBUS input branch; skirt the newly allocated gate pad.
pts=[(89.825,23.605),(89.0,22.78),(89.0,20.635),(91.525,20.635)]
add += [seg(a,b,'/VBUS_RAW',w=.6) for a,b in zip(pts,pts[1:])]
for origin,v,pad,net in [((90.1981,18.7642),(89.9,21.905),(91.525,21.905),'/PMOS_GATE'),((47.4045,41.095),(44.2,44.905),(45.525,44.905),'/FAN_FET_GATE')]:
 add += [seg(origin,v,net,'B.Cu'),via(v,net),seg(v,pad,net)]
s=s.rstrip()[:-1]+''.join(add)+'\n)\n'
pcb=DST/(NEW+'.kicad_pcb');pcb.write_text(s)
for args,name in [(['sch','export','netlist','--format','kicadxml','--output',str(DST/'netlist.xml'),str(DST/(NEW+'.kicad_sch'))],'netlist.log'),(['sch','erc','--format','json','--output',str(DST/'erc.json'),str(DST/(NEW+'.kicad_sch'))],'erc.log'),(['pcb','drc','--format','json','--schematic-parity','--output',str(DST/'drc.json'),str(pcb)],'drc.log')]:
 assert run(args,DST/name)==0
_,pins=netlist(DST/'netlist.xml');_,oldpins=netlist(SRC/'netlist.xml')
changed={str(k):[oldpins[k],v] for k,v in pins.items() if v!=oldpins[k]}
assert set(k for k,v in pins.items() if v!=oldpins[k])=={(r,p) for r in ['Q1','Q3'] for p in ['1','4']}
for _,_,b,r,_ in footprint_rows(s):
 if r not in ['Q1','Q3']:continue
 for _,_,p in forms(b,'pad'):
  pin=re.match(r'\(pad "([^"]+)"',p).group(1);n=re.search(r'\(net "([^"]+)"\)',p).group(1)
  assert n==pins[(r,pin)]
result={'source_board_sha256':sha(SRC/(OLD+'.kicad_pcb')),'candidate_board_sha256':sha(pcb),'changed_pin_nets':changed,'removed_route_segments':len(removed),'added_route_segments_and_vias':len(add),'physical_validation':'NOT_RUN_NO_SAMPLE','manufacturing_status':'FABRICATION_HOLD'}
(ROOT/'pin_fix_checks.json').write_text(json.dumps(result,indent=2)+'\n')
d=json.loads((DST/'drc.json').read_text());print(json.dumps({'checks':result,'violations':len(d['violations']),'unconnected':len(d['unconnected_items']),'parity':len(d['schematic_parity'])},indent=2))
