"""S-expression parser/writer for KiCad library table files (sym-lib-table, fp-lib-table)."""

import re
from pathlib import Path


class LibEntry:
    """Represents a single library entry in a lib table."""

    def __init__(self, name: str, lib_type: str, uri: str,
                 options: str = "", descr: str = ""):
        self.name = name
        self.lib_type = lib_type
        self.uri = uri
        self.options = options
        self.descr = descr

    def to_sexpr(self) -> str:
        return (
            f'  (lib (name "{self.name}")'
            f'(type "{self.lib_type}")'
            f'(uri "{self.uri}")'
            f'(options "{self.options}")'
            f'(descr "{self.descr}"))'
        )


class LibTable:
    """Represents a KiCad sym-lib-table or fp-lib-table."""

    def __init__(self, table_type: str):
        """table_type is 'sym_lib_table' or 'fp_lib_table'."""
        self.table_type = table_type
        self.version: int | None = None  # KiCad 9+ uses (version 7)
        self.entries: list = []

    @classmethod
    def parse_file(cls, filepath: str) -> "LibTable":
        """Parse a lib table file. Creates empty table if file doesn't exist."""
        path = Path(filepath)

        if not path.exists():
            if "sym" in path.name:
                t = cls("sym_lib_table")
            else:
                t = cls("fp_lib_table")
            t.version = 7  # KiCad 9+ expects (version 7)
            return t

        text = path.read_text(encoding="utf-8")
        return cls.parse_string(text)

    @classmethod
    def parse_string(cls, text: str) -> "LibTable":
        """Parse S-expression text into a LibTable."""
        m = re.match(r'\s*\((\w+)', text)
        if not m:
            raise ValueError("Cannot parse lib table: no root expression found")

        table = cls(m.group(1))

        # Parse (version N) if present (KiCad 9+)
        ver_match = re.search(r'\(version\s+(\d+)\)', text)
        if ver_match:
            table.version = int(ver_match.group(1))

        # Match each (lib ...) entry
        lib_pattern = re.compile(
            r'\(lib\s+'
            r'\(name\s+"([^"]*)"\)'
            r'\s*\(type\s+"([^"]*)"\)'
            r'\s*\(uri\s+"([^"]*)"\)'
            r'\s*\(options\s+"([^"]*)"\)'
            r'\s*\(descr\s+"([^"]*)"\)'
            r'\s*\)',
            re.DOTALL
        )

        for m in lib_pattern.finditer(text):
            entry = LibEntry(
                name=m.group(1),
                lib_type=m.group(2),
                uri=m.group(3),
                options=m.group(4),
                descr=m.group(5),
            )
            table.entries.append(entry)

        return table

    def has_library(self, name: str) -> bool:
        """Check if a library with the given name exists."""
        return any(e.name == name for e in self.entries)

    def add_library(self, entry: LibEntry) -> bool:
        """Add a library entry. Returns False if name already exists."""
        if self.has_library(entry.name):
            return False
        self.entries.append(entry)
        return True

    def remove_library(self, name: str) -> bool:
        """Remove a library by name. Returns True if found and removed."""
        before = len(self.entries)
        self.entries = [e for e in self.entries if e.name != name]
        return len(self.entries) < before

    def to_string(self) -> str:
        """Serialize back to S-expression format."""
        lines = [f"({self.table_type}"]
        if self.version is not None:
            lines.append(f"  (version {self.version})")
        for entry in self.entries:
            lines.append(entry.to_sexpr())
        lines.append(")")
        return "\n".join(lines) + "\n"

    def write_file(self, filepath: str):
        """Write the table to a file, creating parent dirs if needed."""
        path = Path(filepath)
        path.parent.mkdir(parents=True, exist_ok=True)
        path.write_text(self.to_string(), encoding="utf-8")


if __name__ == "__main__":
    import sys
    if len(sys.argv) > 1:
        table = LibTable.parse_file(sys.argv[1])
        print(f"Table type: {table.table_type}")
        print(f"Entries: {len(table.entries)}")
        for e in table.entries[:5]:
            print(f"  - {e.name}: {e.uri}")
        if len(table.entries) > 5:
            print(f"  ... and {len(table.entries) - 5} more")
    else:
        print("Usage: python lib_table.py <path-to-lib-table-file>")
