#!/usr/bin/env python3
"""Add the low-cost SYS_5V0_ALWAYS_ON to CTRL_3V3 schematic candidate."""
from pathlib import Path
import uuid
import shutil

HERE=Path(__file__).resolve().parent
SCHEM=HERE/'power_board/lamp_buck_lmr51450_a5_ctrl3v3.kicad_sch'
SYMBOLS=HERE/'power_board/Project.kicad_sym'
shutil.copyfile(HERE/'baseline/lamp_buck_lmr51450_a4_frontend.kicad_sch',SCHEM)
shutil.copyfile(HERE/'baseline/Project.kicad_sym',SYMBOLS)
ROOT='c1e58074-aaa4-41bf-a388-9777c328e970'
NS=uuid.UUID('da744d5c-4499-4740-bb0f-a4c7fc8fb598')
def uid(name): return str(uuid.uuid5(NS,name))
def balanced_end(src,start):
    depth=0; quoted=False; escaped=False
    for i in range(start,len(src)):
        ch=src[i]
        if quoted:
            if escaped: escaped=False
            elif ch=='\\': escaped=True
            elif ch=='"': quoted=False
        else:
            if ch=='"': quoted=True
            elif ch=='(': depth+=1
            elif ch==')':
                depth-=1
                if depth==0: return i+1
    raise ValueError('unbalanced source')

def remove_block(src,start):
    end=balanced_end(src,start)
    return src[:start]+src[end:]

def wire(x1,y1,x2,y2,key):
    return f'(wire (pts (xy {x1} {y1}) (xy {x2} {y2})) (stroke (width 0) (type default)) (uuid "{uid(key)}"))'
def label(name,x,y,key):
    return f'(label "{name}" (at {x} {y} 0) (effects (font (size 1 1)) (justify left bottom)) (uuid "{uid(key)}"))'
def prop(n,v,x,y,hide=False):
    h=' (hide yes)' if hide else ''
    return f'(property "{n}" "{v}" (at {x} {y} 0) (effects (font (size 1 1)){h}))'
def sym_instance(lib,ref,value,footprint,cx,cy,inst_key,refxy,valxy):
    p=[f'(symbol (lib_id "{lib}") (at {cx} {cy} 0) (unit 1) (in_bom yes) (on_board yes) (dnp no) (uuid "{uid(inst_key)}")',
       prop('Reference',ref,*refxy), prop('Value',value,*valxy), prop('Footprint',footprint,cx,cy,True),
       f'(instances (project "lamp_power" (path "/{ROOT}" (reference "{ref}") (unit 1)))))']
    return ''.join(p)

s=SCHEM.read_text()
# Mark the copied source as a new development candidate.
s=s.replace('(rev "A1-dev")','(rev "A2-dev")').replace('ENGINEERING CANDIDATE - NOT FOR FABRICATION','A69 CONTROL RAIL CANDIDATE - NOT FOR FABRICATION')
s=s.replace('AI MINI POWER BOARD A1 - ALWAYS-ON 5.0V SYSTEM RAIL + SEPARATELY GATED LED RAIL','AI MINI POWER BOARD A2 - ALWAYS-ON 5.0V SYSTEM RAIL + SEPARATELY GATED LED RAIL')
# CTRL_3V3 now has a real regulator output; remove its inherited external
# supply marker to avoid representing two schematic power-output drivers.
flag_ref=s.index('(property "Reference" "#FLG3"')
s=remove_block(s,s.rfind('(symbol ',0,flag_ref))
for marker in [
    '(wire (pts (xy 125.73 279.4) (xy 133.35 279.4))',
    '(label "CTRL_3V3" (at 133.35 279.4 0)',
]:
    s=remove_block(s,s.index(marker))
lib_start=s.index('(lib_symbols ')
lib_end=balanced_end(s,lib_start)
lib='''(symbol "Project:AP2112K33" (pin_names (offset 0.8)) (in_bom yes) (on_board yes)
 (property "Reference" "U" (at 0 0 0) (effects (font (size 1 1))))
 (property "Value" "AP2112K-3.3" (at 0 0 0) (effects (font (size 1 1))))
 (symbol "AP2112K33_0_1" (rectangle (start -5.08 5.08) (end 5.08 -5.08) (stroke (width 0.254) (type default)) (fill (type background))))
 (symbol "AP2112K33_1_1"
  (pin power_in line (at -10.16 -2.54 0) (length 5.08) (name "VIN" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1)))))
  (pin power_in line (at 0 -10.16 90) (length 5.08) (name "GND" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1)))))
  (pin input line (at -10.16 2.54 0) (length 5.08) (name "EN" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1)))))
  (pin passive line (at 10.16 2.54 180) (length 5.08) (name "NC" (effects (font (size 1 1)))) (number "4" (effects (font (size 1 1)))))
  (pin power_out line (at 10.16 -2.54 180) (length 5.08) (name "VOUT" (effects (font (size 1 1)))) (number "5" (effects (font (size 1 1)))))))'''
s=s[:lib_end-1]+lib+s[lib_end-1:]
# Keep the project library beside the schematic and include the new symbol.
symbol_lib=SYMBOLS.read_text()
symbol_lib_end=len(symbol_lib.rstrip())-1
symbol_lib=symbol_lib[:symbol_lib_end]+lib.replace('Project:AP2112K33','AP2112K33')+symbol_lib[symbol_lib_end:]
SYMBOLS.write_text(symbol_lib)
# Circuit placement on the far-right portion of the A2 sheet.
items=[]
items.append(sym_instance('Project:AP2112K33','U4','AP2112K-3.3TRG1','Package_TO_SOT_SMD:SOT-23-5',529.59,110.49,'U4',(529.59,93.98),(529.59,96.52)))
items.append(sym_instance('Project:C','C15','1uF 10V X7R','Capacitor_SMD:C_0603_1608Metric',514.35,144.78,'C15',(514.35,132.08),(514.35,134.62)))
items.append(sym_instance('Project:C','C16','1uF 10V X7R','Capacitor_SMD:C_0603_1608Metric',548.64,144.78,'C16',(548.64,132.08),(548.64,134.62)))
# AP2112: pin 1 VIN and pin 3 EN both receive the autonomous always-on 5V rail.
items += [wire(519.43,113.03,511.81,113.03,'U4-W-VIN'), label('SYS_5V0_ALWAYS_ON',511.81,113.03,'U4-L-VIN'),
          wire(519.43,107.95,511.81,107.95,'U4-W-EN'), label('SYS_5V0_ALWAYS_ON',511.81,107.95,'U4-L-EN'),
          wire(529.59,120.65,529.59,125.73,'U4-W-GND'), label('GND',529.59,125.73,'U4-L-GND'),
          wire(539.75,113.03,547.37,113.03,'U4-W-VOUT'), label('CTRL_3V3',547.37,113.03,'U4-L-VOUT'),
          f'(no_connect (at 539.75 107.95) (uuid "{uid("U4-NC")}"))']
# Datasheet minimum 1uF input/output bypass capacitors; MPNs remain cost-down candidates.
items += [wire(514.35,139.7,514.35,134.62,'C15-W-POS'), label('SYS_5V0_ALWAYS_ON',514.35,134.62,'C15-L-POS'),
          wire(514.35,149.86,514.35,154.94,'C15-W-GND'), label('GND',514.35,154.94,'C15-L-GND'),
          wire(548.64,139.7,548.64,134.62,'C16-W-POS'), label('CTRL_3V3',548.64,134.62,'C16-L-POS'),
          wire(548.64,149.86,548.64,154.94,'C16-W-GND'), label('GND',548.64,154.94,'C16-L-GND'),
          f'(text "A69 control rail source; camera UART connector J1.1 remains explicitly NC." (at 500 166 0) (effects (font (size 1.1 1.1)) (justify left)) (uuid "{uid("A2-rail-note")}"))']
# insert all component instances and wires before closing root schematic.
root_end=len(s.rstrip())-1
s=s[:root_end]+''.join(items)+s[root_end:]
SCHEM.write_text(s)
print(f'updated {SCHEM}')
