#!/usr/bin/env python3
"""
Transform firstpcb.kicad_sch:
  1. Remove the L7805 voltage regulator and associated components
  2. Insert the TPS61088 5V→12V boost converter circuit
  3. Keep all other components intact

The +5V and +12V nets connect automatically via KiCad global power symbols.
"""

import re
import uuid
import sys


def uid():
    return str(uuid.uuid4())


ROOT_UUID = "4ce690e5-6d5b-4693-bd2e-f4090f26df1f"


# ── UUIDs of components to REMOVE (L7805 circuit) ──

REMOVE_UUIDS = {
    # L7805 regulator
    "b5b8c784-5cbd-46af-b962-5f07e5e5ce66",
    # C1 (0.33uF) - output cap
    "be10cf51-2c79-49d9-968c-f16a919adeee",
    # C2 (0.1uF) - input cap
    "58617ce4-1b01-4ae9-be22-0491e474e52d",
    # #PWR15 (+5V at L7805 output)
    "dd887245-ee3f-48b0-ab57-caf2a8bdfdef",
    # #PWR19 (+5V at C2)
    "fd8b730d-5d7d-4216-98e6-0f769c039626",
    # #PWR14 (+12V at L7805 input)
    "ea5b2f5d-6233-46fc-93b4-4b52ebc256b5",
    # #PWR17 (+12V at C1)
    "ec47b49b-69a3-415f-b119-7b90e03df83a",
    # #PWR16 (GND under L7805)
    "940ddbc7-3e82-42b5-ad91-3df87e10ff89",
    # #PWR18 (GND under C1)
    "565f28b7-cc4b-427c-be9a-9e09337daabd",
    # #PWR20 (GND under C2)
    "e7fe0926-923d-41aa-92e6-413304613139",
}

REMOVE_WIRE_UUIDS = {
    # Wire: C2 top to L7805 output rail
    "dba247d2-ddb5-46ff-a6bd-5fb718c4599e",
    # Wire: L7805 input to +12V symbol
    "e3772378-2aa5-420d-92e3-94a8234f86b5",
    # Wire: C1 to +12V symbol
    "ee45c424-04dc-4913-92e9-0eec7ac6b273",
    # Wire: L7805 output to +5V symbol
    "48aefa74-f6f4-40ae-9135-90c2565ceadc",
}

# Also remove the L7805 lib_symbol definition
REMOVE_LIB_SYMBOL = "Regulator_Linear:L7805"


def find_block_end(text, start_pos):
    """Find the end of a parenthesized block starting at start_pos.
    start_pos should point to the opening '('."""
    depth = 0
    i = start_pos
    while i < len(text):
        if text[i] == '(':
            depth += 1
        elif text[i] == ')':
            depth -= 1
            if depth == 0:
                return i
        i += 1
    return -1


def remove_blocks_by_uuid(text, uuids):
    """Remove top-level blocks (symbol, wire, junction) containing matching UUIDs."""
    for u in uuids:
        # Find the UUID in the text
        pattern = f'(uuid "{u}")'
        idx = text.find(pattern)
        if idx == -1:
            print(f"  WARNING: UUID {u} not found, skipping", file=sys.stderr)
            continue

        # Walk backward from UUID to find the containing block's opening
        # Look for a tab-indented opening paren: \n\t(symbol, \n\t(wire, etc.
        search_start = idx
        block_start = -1
        while search_start > 0:
            # Find the previous newline
            nl = text.rfind('\n', 0, search_start)
            if nl == -1:
                break
            line = text[nl+1:search_start]
            # Check if this line starts a top-level block
            stripped = line.lstrip()
            if stripped.startswith('(symbol') or stripped.startswith('(wire') or \
               stripped.startswith('(junction') or stripped.startswith('(no_connect'):
                block_start = nl + 1
                # Find the start of the actual paren
                paren_pos = text.index('(', block_start)
                block_start = paren_pos
                break
            search_start = nl

        if block_start == -1:
            print(f"  WARNING: Could not find block start for UUID {u}", file=sys.stderr)
            continue

        block_end = find_block_end(text, block_start)
        if block_end == -1:
            print(f"  WARNING: Could not find block end for UUID {u}", file=sys.stderr)
            continue

        # Remove the block (including trailing newline)
        end = block_end + 1
        if end < len(text) and text[end] == '\n':
            end += 1

        # Also remove leading whitespace/tabs on the same line
        while block_start > 0 and text[block_start-1] in '\t ':
            block_start -= 1

        print(f"  Removing block with UUID {u[:12]}... ({end - block_start} chars)")
        text = text[:block_start] + text[end:]

    return text


def remove_lib_symbol(text, lib_id):
    """Remove a lib_symbol definition from the lib_symbols section."""
    pattern = f'(symbol "{lib_id}"'
    idx = text.find(pattern)
    if idx == -1:
        print(f"  WARNING: lib_symbol {lib_id} not found", file=sys.stderr)
        return text

    # Find the containing (symbol block - walk back to find the right indentation
    # In lib_symbols, entries are indented with two tabs
    search = idx
    while search > 0 and text[search-1] != '\n':
        search -= 1
    block_start = search

    block_paren = text.index('(', block_start)
    block_end = find_block_end(text, block_paren)

    end = block_end + 1
    if end < len(text) and text[end] == '\n':
        end += 1

    print(f"  Removing lib_symbol {lib_id}")
    text = text[:block_start] + text[end:]
    return text


# ── TPS61088 boost converter circuit to INSERT ──

def gen_symbol(lib_id, ref, value, x, y, rot=0, pins=None, extra_props=""):
    """Generate a symbol placement block."""
    u = uid()
    if pins is None:
        pins = {}
    pin_str = ""
    for pnum in sorted(pins.keys(), key=lambda k: int(k) if k.isdigit() else k):
        pin_str += f'\t\t(pin "{pnum}"\n\t\t\t(uuid "{pins[pnum]}")\n\t\t)\n'

    return f"""\t(symbol
\t\t(lib_id "{lib_id}")
\t\t(at {round(x, 2)} {round(y, 2)} {rot})
\t\t(unit 1)
\t\t(exclude_from_sim no)
\t\t(in_bom yes)
\t\t(on_board yes)
\t\t(dnp no)
\t\t(uuid "{u}")
\t\t(property "Reference" "{ref}"
\t\t\t(at {round(x + 2.54, 2)} {round(y - 2.54, 2)} 0)
\t\t\t(effects
\t\t\t\t(font
\t\t\t\t\t(size 1.27 1.27)
\t\t\t\t)
\t\t\t\t(justify left)
\t\t\t)
\t\t)
\t\t(property "Value" "{value}"
\t\t\t(at {round(x + 2.54, 2)} {round(y + 2.54, 2)} 0)
\t\t\t(effects
\t\t\t\t(font
\t\t\t\t\t(size 1.27 1.27)
\t\t\t\t)
\t\t\t\t(justify left)
\t\t\t)
\t\t)
\t\t(property "Footprint" ""
\t\t\t(at {round(x, 2)} {round(y, 2)} 0)
\t\t\t(effects
\t\t\t\t(font
\t\t\t\t\t(size 1.27 1.27)
\t\t\t\t)
\t\t\t\t(hide yes)
\t\t\t)
\t\t)
\t\t(property "Datasheet" ""
\t\t\t(at {round(x, 2)} {round(y, 2)} 0)
\t\t\t(effects
\t\t\t\t(font
\t\t\t\t\t(size 1.27 1.27)
\t\t\t\t)
\t\t\t\t(hide yes)
\t\t\t)
\t\t)
\t\t(property "Description" ""
\t\t\t(at {round(x, 2)} {round(y, 2)} 0)
\t\t\t(effects
\t\t\t\t(font
\t\t\t\t\t(size 1.27 1.27)
\t\t\t\t)
\t\t\t\t(hide yes)
\t\t\t)
\t\t){extra_props}
{pin_str}\t\t(instances
\t\t\t(project ""
\t\t\t\t(path "/{ROOT_UUID}"
\t\t\t\t\t(reference "{ref}")
\t\t\t\t\t(unit 1)
\t\t\t\t)
\t\t\t)
\t\t)
\t)"""


def gen_pwr(lib_id, value, x, y, ref):
    """Generate a power symbol block."""
    return f"""\t(symbol
\t\t(lib_id "{lib_id}")
\t\t(at {round(x, 2)} {round(y, 2)} 0)
\t\t(unit 1)
\t\t(exclude_from_sim no)
\t\t(in_bom yes)
\t\t(on_board yes)
\t\t(dnp no)
\t\t(uuid "{uid()}")
\t\t(property "Reference" "{ref}"
\t\t\t(at {round(x, 2)} {round(y - 2.54, 2)} 0)
\t\t\t(effects
\t\t\t\t(font
\t\t\t\t\t(size 1.27 1.27)
\t\t\t\t)
\t\t\t\t(hide yes)
\t\t\t)
\t\t)
\t\t(property "Value" "{value}"
\t\t\t(at {round(x, 2)} {round(y + 3.81, 2)} 0)
\t\t\t(effects
\t\t\t\t(font
\t\t\t\t\t(size 1.27 1.27)
\t\t\t\t)
\t\t\t)
\t\t)
\t\t(property "Footprint" ""
\t\t\t(at {round(x, 2)} {round(y, 2)} 0)
\t\t\t(effects
\t\t\t\t(font
\t\t\t\t\t(size 1.27 1.27)
\t\t\t\t)
\t\t\t\t(hide yes)
\t\t\t)
\t\t)
\t\t(property "Datasheet" ""
\t\t\t(at {round(x, 2)} {round(y, 2)} 0)
\t\t\t(effects
\t\t\t\t(font
\t\t\t\t\t(size 1.27 1.27)
\t\t\t\t)
\t\t\t\t(hide yes)
\t\t\t)
\t\t)
\t\t(property "Description" ""
\t\t\t(at {round(x, 2)} {round(y, 2)} 0)
\t\t\t(effects
\t\t\t\t(font
\t\t\t\t\t(size 1.27 1.27)
\t\t\t\t)
\t\t\t\t(hide yes)
\t\t\t)
\t\t)
\t\t(pin "1"
\t\t\t(uuid "{uid()}")
\t\t)
\t\t(instances
\t\t\t(project ""
\t\t\t\t(path "/{ROOT_UUID}"
\t\t\t\t\t(reference "{ref}")
\t\t\t\t\t(unit 1)
\t\t\t\t)
\t\t\t)
\t\t)
\t)"""


def gen_wire(x1, y1, x2, y2):
    return f"""\t(wire
\t\t(pts
\t\t\t(xy {round(x1, 2)} {round(y1, 2)}) (xy {round(x2, 2)} {round(y2, 2)})
\t\t)
\t\t(stroke
\t\t\t(width 0)
\t\t\t(type default)
\t\t)
\t\t(uuid "{uid()}")
\t)"""


def gen_junction(x, y):
    return f"""\t(junction
\t\t(at {round(x, 2)} {round(y, 2)})
\t\t(diameter 0)
\t\t(color 0 0 0 0)
\t\t(uuid "{uid()}")
\t)"""


def gen_label(x, y, name, rot=0):
    return f"""\t(label "{name}"
\t\t(at {round(x, 2)} {round(y, 2)} {rot})
\t\t(effects
\t\t\t(font
\t\t\t\t(size 1.27 1.27)
\t\t\t)
\t\t)
\t\t(uuid "{uid()}")
\t)"""


def gen_no_connect(x, y):
    return f"""\t(no_connect
\t\t(at {round(x, 2)} {round(y, 2)})
\t\t(uuid "{uid()}")
\t)"""


def gen_text(x, y, text):
    return f"""\t(text "{text}"
\t\t(exclude_from_sim no)
\t\t(at {round(x, 2)} {round(y, 2)} 0)
\t\t(effects
\t\t\t(font
\t\t\t\t(size 1.27 1.27)
\t\t\t)
\t\t\t(justify left)
\t\t)
\t\t(uuid "{uid()}")
\t)"""


# ── TPS61088 lib_symbol definition ──

TPS61088_LIB_SYMBOL = """\t\t(symbol "TPS61088:TPS61088"
\t\t\t(exclude_from_sim no)
\t\t\t(in_bom yes)
\t\t\t(on_board yes)
\t\t\t(property "Reference" "U"
\t\t\t\t(at 0 16.51 0)
\t\t\t\t(effects (font (size 1.27 1.27)))
\t\t\t)
\t\t\t(property "Value" "TPS61088"
\t\t\t\t(at 0 13.97 0)
\t\t\t\t(effects (font (size 1.27 1.27)))
\t\t\t)
\t\t\t(property "Footprint" "Package_DFN_QFN:QFN-20-1EP_3.5x3.5mm_P0.5mm_EP2.1x2.1mm"
\t\t\t\t(at 0 -20.32 0)
\t\t\t\t(effects (font (size 1.27 1.27)) (hide yes))
\t\t\t)
\t\t\t(property "Datasheet" "https://www.ti.com/lit/ds/symlink/tps61088.pdf"
\t\t\t\t(at 0 -22.86 0)
\t\t\t\t(effects (font (size 1.27 1.27)) (hide yes))
\t\t\t)
\t\t\t(property "Description" "10A Fully-Integrated Synchronous Boost Converter"
\t\t\t\t(at 0 -25.4 0)
\t\t\t\t(effects (font (size 1.27 1.27)) (hide yes))
\t\t\t)
\t\t\t(symbol "TPS61088_0_1"
\t\t\t\t(rectangle
\t\t\t\t\t(start -10.16 12.7)
\t\t\t\t\t(end 10.16 -12.7)
\t\t\t\t\t(stroke (width 0.254) (type default))
\t\t\t\t\t(fill (type background))
\t\t\t\t)
\t\t\t)
\t\t\t(symbol "TPS61088_1_1"
\t\t\t\t(pin power_in line
\t\t\t\t\t(at -12.7 10.16 0) (length 2.54)
\t\t\t\t\t(name "VIN" (effects (font (size 1.27 1.27))))
\t\t\t\t\t(number "1" (effects (font (size 1.27 1.27))))
\t\t\t\t)
\t\t\t\t(pin input line
\t\t\t\t\t(at -12.7 5.08 0) (length 2.54)
\t\t\t\t\t(name "EN" (effects (font (size 1.27 1.27))))
\t\t\t\t\t(number "3" (effects (font (size 1.27 1.27))))
\t\t\t\t)
\t\t\t\t(pin passive line
\t\t\t\t\t(at -12.7 0 0) (length 2.54)
\t\t\t\t\t(name "SS/TR" (effects (font (size 1.27 1.27))))
\t\t\t\t\t(number "4" (effects (font (size 1.27 1.27))))
\t\t\t\t)
\t\t\t\t(pin passive line
\t\t\t\t\t(at -12.7 -5.08 0) (length 2.54)
\t\t\t\t\t(name "COMP" (effects (font (size 1.27 1.27))))
\t\t\t\t\t(number "5" (effects (font (size 1.27 1.27))))
\t\t\t\t)
\t\t\t\t(pin input line
\t\t\t\t\t(at -12.7 -10.16 0) (length 2.54)
\t\t\t\t\t(name "FB" (effects (font (size 1.27 1.27))))
\t\t\t\t\t(number "6" (effects (font (size 1.27 1.27))))
\t\t\t\t)
\t\t\t\t(pin passive line
\t\t\t\t\t(at 12.7 10.16 180) (length 2.54)
\t\t\t\t\t(name "SW" (effects (font (size 1.27 1.27))))
\t\t\t\t\t(number "12" (effects (font (size 1.27 1.27))))
\t\t\t\t)
\t\t\t\t(pin passive line
\t\t\t\t\t(at 12.7 5.08 180) (length 2.54)
\t\t\t\t\t(name "BST" (effects (font (size 1.27 1.27))))
\t\t\t\t\t(number "11" (effects (font (size 1.27 1.27))))
\t\t\t\t)
\t\t\t\t(pin power_out line
\t\t\t\t\t(at 12.7 0 180) (length 2.54)
\t\t\t\t\t(name "VOUT" (effects (font (size 1.27 1.27))))
\t\t\t\t\t(number "9" (effects (font (size 1.27 1.27))))
\t\t\t\t)
\t\t\t\t(pin open_collector line
\t\t\t\t\t(at 12.7 -5.08 180) (length 2.54)
\t\t\t\t\t(name "PGOOD" (effects (font (size 1.27 1.27))))
\t\t\t\t\t(number "8" (effects (font (size 1.27 1.27))))
\t\t\t\t)
\t\t\t\t(pin power_in line
\t\t\t\t\t(at 0 -15.24 90) (length 2.54)
\t\t\t\t\t(name "PGND" (effects (font (size 1.27 1.27))))
\t\t\t\t\t(number "15" (effects (font (size 1.27 1.27))))
\t\t\t\t)
\t\t\t\t(pin power_in line
\t\t\t\t\t(at -5.08 -15.24 90) (length 2.54)
\t\t\t\t\t(name "AGND" (effects (font (size 1.27 1.27))))
\t\t\t\t\t(number "7" (effects (font (size 1.27 1.27))))
\t\t\t\t)
\t\t\t)
\t\t\t(embedded_fonts no)
\t\t)"""


def generate_boost_circuit():
    """Generate all the schematic elements for the TPS61088 boost converter.
    Returns (junctions, wires, labels, no_connects, texts, symbols) as lists of strings.

    Placed below the main circuit, centered around (80, 140).
    """
    junctions = []
    wires = []
    labels = []
    no_connects = []
    texts = []
    symbols = []

    pwr_idx = [30]  # start well after existing power refs (existing go up to #PWR23)
    def next_pwr():
        pwr_idx[0] += 1
        return f"#PWR{pwr_idx[0]:02d}"

    # IC center
    cx, cy = 80.01, 140.97

    # Pin absolute positions
    VIN  = (cx - 12.7, cy - 10.16)
    EN   = (cx - 12.7, cy - 5.08)
    SS   = (cx - 12.7, cy)
    COMP = (cx - 12.7, cy + 5.08)
    FB   = (cx - 12.7, cy + 10.16)
    SW   = (cx + 12.7, cy - 10.16)
    BST  = (cx + 12.7, cy - 5.08)
    VOUT = (cx + 12.7, cy)
    PG   = (cx + 12.7, cy + 5.08)
    PGND = (cx, cy + 15.24)
    AGND = (cx - 5.08, cy + 15.24)

    # Place TPS61088 IC
    ic_pins = {str(i): uid() for i in [1, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15]}
    symbols.append(gen_symbol("TPS61088:TPS61088", "U1", "TPS61088", cx, cy, pins=ic_pins))

    # ── INPUT SECTION ──
    vin_rail_y = VIN[1]
    pwr5v_x = 39.37
    c1_x = 44.45
    c2_x = 52.07
    en_tap_x = 59.69

    # +5V source
    ref = next_pwr()
    symbols.append(gen_pwr("power:+5V", "+5V", pwr5v_x, vin_rail_y - 5.08, ref))
    wires.append(gen_wire(pwr5v_x, vin_rail_y - 5.08, pwr5v_x, vin_rail_y))

    # VIN rail (segmented)
    wires.append(gen_wire(pwr5v_x, vin_rail_y, c1_x, vin_rail_y))
    wires.append(gen_wire(c1_x, vin_rail_y, c2_x, vin_rail_y))
    wires.append(gen_wire(c2_x, vin_rail_y, en_tap_x, vin_rail_y))
    wires.append(gen_wire(en_tap_x, vin_rail_y, VIN[0], vin_rail_y))

    # C1 input cap (22µF) — using Device:C (pins at ±3.81)
    c1_cy = vin_rail_y + 6.35
    symbols.append(gen_symbol("Device:C", "C4", "22uF", c1_x, c1_cy,
                              pins={"1": uid(), "2": uid()}))
    wires.append(gen_wire(c1_x, c1_cy - 3.81, c1_x, vin_rail_y))
    ref = next_pwr()
    symbols.append(gen_pwr("power:GND", "GND", c1_x, c1_cy + 6.35, ref))
    wires.append(gen_wire(c1_x, c1_cy + 3.81, c1_x, c1_cy + 6.35))

    # C2 input cap (22µF)
    c2_cy = vin_rail_y + 6.35
    symbols.append(gen_symbol("Device:C", "C5", "22uF", c2_x, c2_cy,
                              pins={"1": uid(), "2": uid()}))
    wires.append(gen_wire(c2_x, c2_cy - 3.81, c2_x, vin_rail_y))
    ref = next_pwr()
    symbols.append(gen_pwr("power:GND", "GND", c2_x, c2_cy + 6.35, ref))
    wires.append(gen_wire(c2_x, c2_cy + 3.81, c2_x, c2_cy + 6.35))

    # EN tied to VIN
    wires.append(gen_wire(EN[0], EN[1], en_tap_x, EN[1]))
    wires.append(gen_wire(en_tap_x, EN[1], en_tap_x, vin_rail_y))

    # ── SOFT-START ──
    ss_x = 59.69
    c3_cy = SS[1] + 6.35
    wires.append(gen_wire(SS[0], SS[1], ss_x, SS[1]))
    symbols.append(gen_symbol("Device:C", "C6", "22nF", ss_x, c3_cy,
                              pins={"1": uid(), "2": uid()}))
    wires.append(gen_wire(ss_x, SS[1], ss_x, c3_cy - 3.81))
    ref = next_pwr()
    symbols.append(gen_pwr("power:GND", "GND", ss_x, c3_cy + 6.35, ref))
    wires.append(gen_wire(ss_x, c3_cy + 3.81, ss_x, c3_cy + 6.35))

    # ── COMPENSATION ──
    comp_x = 52.07
    r1_y = COMP[1] + 6.35
    wires.append(gen_wire(COMP[0], COMP[1], comp_x, COMP[1]))
    symbols.append(gen_symbol("Device:R", "R3", "30.1k", comp_x, r1_y,  # COMP resistor
                              pins={"1": uid(), "2": uid()}))
    wires.append(gen_wire(comp_x, COMP[1], comp_x, r1_y - 3.81))

    c4_y = r1_y + 10.16
    symbols.append(gen_symbol("Device:C", "C8", "47pF", comp_x, c4_y,
                              pins={"1": uid(), "2": uid()}))
    wires.append(gen_wire(comp_x, r1_y + 3.81, comp_x, c4_y - 3.81))
    ref = next_pwr()
    symbols.append(gen_pwr("power:GND", "GND", comp_x, c4_y + 6.35, ref))
    wires.append(gen_wire(comp_x, c4_y + 3.81, comp_x, c4_y + 6.35))

    # ── IC GROUND ──
    gnd_y = PGND[1] + 5.08
    ref = next_pwr()
    symbols.append(gen_pwr("power:GND", "GND", PGND[0], gnd_y, ref))
    wires.append(gen_wire(PGND[0], PGND[1], PGND[0], gnd_y))
    wires.append(gen_wire(AGND[0], AGND[1], AGND[0], gnd_y))
    wires.append(gen_wire(AGND[0], gnd_y, PGND[0], gnd_y))
    junctions.append(gen_junction(PGND[0], gnd_y))

    # ── OUTPUT SECTION ──
    c5_x = 97.79
    l1_x = 102.87
    l1_y = SW[1]
    l1_pin1 = (l1_x - 3.81, l1_y)
    l1_pin2 = (l1_x + 3.81, l1_y)

    symbols.append(gen_symbol("Device:L", "L1", "2.2uH", l1_x, l1_y, rot=90,
                              pins={"1": uid(), "2": uid()}))

    # SW → C5 junction → L1
    wires.append(gen_wire(SW[0], SW[1], c5_x, SW[1]))
    wires.append(gen_wire(c5_x, SW[1], l1_pin1[0], l1_pin1[1]))

    # Bootstrap cap C5 (100nF)
    c5_cy = SW[1] + 3.81
    symbols.append(gen_symbol("Device:C", "C9", "100nF", c5_x, c5_cy,
                              pins={"1": uid(), "2": uid()}))
    junctions.append(gen_junction(c5_x, SW[1]))
    wires.append(gen_wire(c5_x, c5_cy + 3.81, BST[0], BST[1]))

    # VOUT rail
    vout_rail_x = 115.57
    wires.append(gen_wire(l1_pin2[0], l1_pin2[1], vout_rail_x, l1_y))
    wires.append(gen_wire(VOUT[0], VOUT[1], vout_rail_x, VOUT[1]))
    wires.append(gen_wire(vout_rail_x, l1_y, vout_rail_x, VOUT[1]))

    # Output caps
    c6_x = 120.65
    c7_x = 128.27

    wires.append(gen_wire(vout_rail_x, l1_y, c6_x, l1_y))
    wires.append(gen_wire(c6_x, l1_y, c7_x, l1_y))

    c6_cy = l1_y + 6.35
    symbols.append(gen_symbol("Device:C", "C10", "22uF", c6_x, c6_cy,
                              pins={"1": uid(), "2": uid()}))
    wires.append(gen_wire(c6_x, c6_cy - 3.81, c6_x, l1_y))
    ref = next_pwr()
    symbols.append(gen_pwr("power:GND", "GND", c6_x, c6_cy + 6.35, ref))
    wires.append(gen_wire(c6_x, c6_cy + 3.81, c6_x, c6_cy + 6.35))

    c7_cy = l1_y + 6.35
    symbols.append(gen_symbol("Device:C", "C11", "22uF", c7_x, c7_cy,
                              pins={"1": uid(), "2": uid()}))
    wires.append(gen_wire(c7_x, c7_cy - 3.81, c7_x, l1_y))
    ref = next_pwr()
    symbols.append(gen_pwr("power:GND", "GND", c7_x, c7_cy + 6.35, ref))
    wires.append(gen_wire(c7_x, c7_cy + 3.81, c7_x, c7_cy + 6.35))

    # +12V output
    ref = next_pwr()
    symbols.append(gen_pwr("power:+12V", "+12V", c7_x, l1_y - 5.08, ref))
    wires.append(gen_wire(c7_x, l1_y, c7_x, l1_y - 5.08))
    junctions.append(gen_junction(c7_x, l1_y))

    # ── FEEDBACK DIVIDER ──
    fb_x = vout_rail_x
    r2_y = VOUT[1] + 6.35
    symbols.append(gen_symbol("Device:R", "R4", "190k", fb_x, r2_y,
                              pins={"1": uid(), "2": uid()}))
    wires.append(gen_wire(fb_x, VOUT[1], fb_x, r2_y - 3.81))
    junctions.append(gen_junction(fb_x, VOUT[1]))

    r3_y = r2_y + 10.16
    symbols.append(gen_symbol("Device:R", "R5", "10k", fb_x, r3_y,
                              pins={"1": uid(), "2": uid()}))
    wires.append(gen_wire(fb_x, r2_y + 3.81, fb_x, r3_y - 3.81))

    # FB tap label
    fb_tap_y = r2_y + 3.81
    wires.append(gen_wire(fb_x, fb_tap_y, fb_x + 5.08, fb_tap_y))
    labels.append(gen_label(fb_x + 5.08, fb_tap_y, "FB"))
    junctions.append(gen_junction(fb_x, fb_tap_y))

    # FB label at IC
    wires.append(gen_wire(FB[0], FB[1], FB[0] - 5.08, FB[1]))
    labels.append(gen_label(FB[0] - 5.08, FB[1], "FB", rot=180))

    # R3 to GND
    ref = next_pwr()
    symbols.append(gen_pwr("power:GND", "GND", fb_x, r3_y + 6.35, ref))
    wires.append(gen_wire(fb_x, r3_y + 3.81, fb_x, r3_y + 6.35))

    # PGOOD no connect
    no_connects.append(gen_no_connect(PG[0], PG[1]))

    # ── NOTES ──
    nx = 39.37
    ny = 177.8
    texts.append(gen_text(nx, ny, "TPS61088 Boost: 5V to 12V @ 2A"))
    texts.append(gen_text(nx, ny + 3.81, "VOUT = 0.6V x (1 + 190k/10k) = 12.06V"))

    return junctions, wires, labels, no_connects, texts, symbols


def main():
    infile = "firstpcb.kicad_sch"
    outfile = "firstpcb.kicad_sch"

    print(f"Reading {infile}...")
    with open(infile, "r") as f:
        text = f.read()

    # Step 1: Remove L7805 lib_symbol
    print("\nRemoving L7805 lib_symbol...")
    text = remove_lib_symbol(text, REMOVE_LIB_SYMBOL)

    # Step 2: Remove wires first (they reference removed components)
    print("\nRemoving L7805 circuit wires...")
    text = remove_blocks_by_uuid(text, REMOVE_WIRE_UUIDS)

    # Step 3: Remove components and power symbols
    print("\nRemoving L7805 circuit components...")
    text = remove_blocks_by_uuid(text, REMOVE_UUIDS)

    # Step 4: Add TPS61088 lib_symbol to lib_symbols section
    print("\nAdding TPS61088 lib_symbol...")
    # Find end of lib_symbols section (look for the closing paren before first junction/wire/label/symbol)
    # The lib_symbols section ends with a line like "\t)"
    # Find the pattern: a tab + ) that comes after all symbol definitions
    lib_end_marker = "\n\t)\n"
    # Find the FIRST occurrence of this pattern after "(lib_symbols"
    lib_start = text.find("(lib_symbols")
    if lib_start == -1:
        print("ERROR: Could not find lib_symbols section", file=sys.stderr)
        sys.exit(1)

    # Find the end of lib_symbols by tracking paren depth
    lib_paren = text.index("(", lib_start)
    lib_end = find_block_end(text, lib_paren)
    # Insert before the closing paren
    insert_pos = lib_end
    # Read Device:L lib_symbol from KiCad library (not embedded in this schematic)
    device_l_sym = ""
    kicad_sym_paths = [
        "/nix/store/pbwczj1nsp823njj1kkw75a99jmkz958-kicad-symbols-884133df0a/share/kicad/symbols/Device.kicad_sym",
        "/nix/store/6yiq36yhskjhga4mw63ypbw2wcb4f4m9-kicad-symbols-884133df0a/share/kicad/symbols/Device.kicad_sym",
    ]
    for path in kicad_sym_paths:
        try:
            with open(path) as lf:
                ltext = lf.read()
            ls = ltext.find('\n\t(symbol "L"')
            if ls != -1:
                ls += 1
                li = ls
                while ltext[li] != '(':
                    li += 1
                ldepth = 0
                lpos = li
                while lpos < len(ltext):
                    if ltext[lpos] == '(':
                        ldepth += 1
                    elif ltext[lpos] == ')':
                        ldepth -= 1
                        if ldepth == 0:
                            device_l_sym = ltext[ls:lpos+1]
                            device_l_sym = device_l_sym.replace('(symbol "L"', '(symbol "Device:L"', 1)
                            # Add extra tab for nesting inside lib_symbols
                            device_l_sym = '\n'.join('\t' + line for line in device_l_sym.split('\n'))
                            print(f"  Loaded Device:L from {path}")
                            break
                    lpos += 1
            if device_l_sym:
                break
        except FileNotFoundError:
            continue

    text = text[:insert_pos] + "\n" + TPS61088_LIB_SYMBOL + "\n" + device_l_sym + "\n\t" + text[insert_pos:]

    # Step 5: Generate and insert boost converter circuit
    print("\nGenerating TPS61088 boost converter circuit...")
    juncs, wires, lbls, ncs, txts, syms = generate_boost_circuit()

    # Insert before (sheet_instances
    sheet_marker = "\t(sheet_instances"
    sheet_pos = text.find(sheet_marker)
    if sheet_pos == -1:
        print("ERROR: Could not find sheet_instances", file=sys.stderr)
        sys.exit(1)

    insert_blocks = []
    insert_blocks.extend(juncs)
    insert_blocks.extend(ncs)
    insert_blocks.extend(wires)
    insert_blocks.extend(lbls)
    insert_blocks.extend(txts)
    insert_blocks.extend(syms)

    insert_text = "\n".join(insert_blocks) + "\n"
    text = text[:sheet_pos] + insert_text + text[sheet_pos:]

    # Step 6: Write output
    print(f"\nWriting {outfile}...")
    with open(outfile, "w") as f:
        f.write(text)

    print("Done! Open in KiCad to review.")


if __name__ == "__main__":
    main()
