"""Handler for install_library command."""

import re
import shutil
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent.parent))
from lib_table import LibTable, LibEntry

# Map library type to configuration
LIB_TYPE_CONFIG = {
    "symbol": {
        "table_file": "sym-lib-table",
        "table_type": "sym_lib_table",
        "user_subdir": "symbols",
        "kicad_type": "KiCad",
    },
    "footprint": {
        "table_file": "fp-lib-table",
        "table_type": "fp_lib_table",
        "user_subdir": "footprints",
        "kicad_type": "KiCad",
    },
}


def _install_footprint(kicad_info: dict, args: dict) -> dict:
    """Install a footprint library (.kicad_mod → .pretty directory)."""
    lib_path = args.get("libraryPath", "")
    lib_name = args.get("libraryName", "")
    description = args.get("description", "Installed by Adom Desktop")
    model_3d_path = args.get("model3dPath", "")

    source = Path(lib_path)
    if not source.exists():
        return {
            "success": False,
            "error": f"Footprint source not found: {lib_path}",
            "_hint": "The path may exist on Docker but not on the Windows host. Use push_file to copy from Docker first, or verify the host-side path.",
        }

    config_dir = kicad_info.get("config_dir")
    user_dir = kicad_info.get("user_dir")
    if not config_dir or not user_dir:
        return {"success": False, "error": "KiCad config/user directory not found"}

    # Footprint libraries are .pretty directories containing .kicad_mod files
    footprints_dir = Path(user_dir) / "footprints"
    footprints_dir.mkdir(parents=True, exist_ok=True)

    if source.is_dir() and source.suffix == ".pretty":
        # Source is already a .pretty directory — copy as-is
        if not lib_name:
            lib_name = source.stem
        pretty_dir = footprints_dir / source.name
        if pretty_dir.exists():
            shutil.rmtree(pretty_dir)
        shutil.copytree(str(source), str(pretty_dir))
    elif source.suffix == ".kicad_mod":
        # Single .kicad_mod file — wrap in a .pretty directory
        if not lib_name:
            lib_name = source.stem
        pretty_name = f"{lib_name}.pretty"
        pretty_dir = footprints_dir / pretty_name
        pretty_dir.mkdir(parents=True, exist_ok=True)

        # KiCad requires the .kicad_mod filename to match the footprint name
        # declared inside the file. Extract it and rename if needed.
        fp_text = source.read_text(encoding="utf-8")
        fp_name_match = re.search(r'\(footprint "([^"]+)"', fp_text)
        if fp_name_match:
            correct_name = f"{fp_name_match.group(1)}.kicad_mod"
        else:
            correct_name = source.name
        dest_file = pretty_dir / correct_name
        shutil.copy2(str(source), str(dest_file))
    else:
        return {
            "success": False,
            "error": f"Invalid footprint source: expected .kicad_mod file or .pretty directory, got {source.name}",
        }

    # Install 3D model if provided
    model_installed_path = ""
    if model_3d_path:
        model_source = Path(model_3d_path)
        if model_source.exists():
            models_dir = Path(user_dir) / "3dmodels" / f"{lib_name}.3dshapes"
            models_dir.mkdir(parents=True, exist_ok=True)
            model_dest = models_dir / model_source.name
            shutil.copy2(str(model_source), str(model_dest))
            model_installed_path = str(model_dest).replace("\\", "/")

            # Update the footprint file to add the 3D model reference
            if source.suffix == ".kicad_mod":
                _add_model_to_footprint(pretty_dir / source.name, model_installed_path)

    # Register in fp-lib-table
    table_path = Path(config_dir) / "fp-lib-table"
    table = LibTable.parse_file(str(table_path))

    uri = str(pretty_dir).replace("\\", "/")

    if not table.has_library(lib_name):
        entry = LibEntry(
            name=lib_name,
            lib_type="KiCad",
            uri=uri,
            options="",
            descr=description,
        )
        table.add_library(entry)
        table.write_file(str(table_path))
        registered = True
    else:
        registered = False

    result = {
        "success": True,
        "output": f"Footprint library '{lib_name}' installed to {pretty_dir}"
                  + (f" (already registered)" if not registered else f" and registered in fp-lib-table"),
        "data": {
            "name": lib_name,
            "path": str(pretty_dir),
            "table": "fp-lib-table",
        },
        "_hint": (
            f"✅ Footprint library '{lib_name}' is now in fp-lib-table. "
            f"For next-time confidence, run `kicad_lint_library '{{\"libraryPath\":\"<path-to-.pretty-dir>\"}}'` "
            f"BEFORE install to validate each .kicad_mod inside in ~100ms (catches malformed files, "
            f"outdated formats). Any open KiCad windows need to be closed + reopened to pick up the new "
            f"fp-lib-table entry."
        ),
    }
    if model_installed_path:
        result["data"]["model3dPath"] = model_installed_path
        result["output"] += f". 3D model installed to {model_installed_path}"

    return result


def _add_model_to_footprint(footprint_path: Path, model_path: str):
    """Add a (model ...) reference to a .kicad_mod file."""
    text = footprint_path.read_text(encoding="utf-8")

    # Remove any existing model reference
    text = re.sub(r'\s*\(model\s+"[^"]*"[^)]*\(offset[^)]*\)[^)]*\(scale[^)]*\)[^)]*\(rotate[^)]*\)\s*\)', '', text)

    # Insert model reference before the final closing paren
    model_block = (
        f'\n  (model "{model_path}"\n'
        f'    (offset (xyz 0 0 0))\n'
        f'    (scale (xyz 1 1 1))\n'
        f'    (rotate (xyz 0 0 0))\n'
        f'  )'
    )
    # Find last ) and insert before it
    idx = text.rfind(")")
    if idx >= 0:
        text = text[:idx] + model_block + "\n" + text[idx:]

    footprint_path.write_text(text, encoding="utf-8")


def handle_install_library(kicad_info: dict, args: dict) -> dict:
    """Install a library into KiCad's global lib table."""
    if not kicad_info.get("installed"):
        return {
            "success": False,
            "error": "KiCad not installed",
            "_hint": "Report to the user and ask them to install KiCad from https://www.kicad.org/download/, then retry.",
        }

    lib_path = args.get("libraryPath", "")
    lib_type = args.get("libraryType", "symbol")

    if not lib_path:
        return {"success": False, "error": "No libraryPath specified"}

    # Footprints need special handling (.pretty directories)
    if lib_type == "footprint":
        return _install_footprint(kicad_info, args)

    # --- Symbol library install (original logic) ---
    lib_name = args.get("libraryName", "")
    description = args.get("description", "Installed by Adom Desktop")

    source = Path(lib_path)
    if not source.exists():
        return {
            "success": False,
            "error": f"Library source not found: {lib_path}",
            "_hint": "The path may exist on Docker but not on the Windows host. Use push_file to copy from Docker first, or verify the host-side path.",
        }

    if not lib_name:
        lib_name = source.stem

    type_config = LIB_TYPE_CONFIG.get(lib_type)
    if not type_config:
        return {
            "success": False,
            "error": f"Unknown library type: {lib_type}. Use 'symbol' or 'footprint'",
        }

    config_dir = kicad_info.get("config_dir")
    if not config_dir:
        return {"success": False, "error": "KiCad config directory not found"}

    user_dir = kicad_info.get("user_dir")
    if not user_dir:
        return {"success": False, "error": "KiCad user directory not found"}

    # Copy library file to user's library directory
    dest_dir = Path(user_dir) / type_config["user_subdir"]
    dest_dir.mkdir(parents=True, exist_ok=True)

    if source.is_dir():
        dest = dest_dir / source.name
        if dest.exists():
            shutil.rmtree(dest)
        shutil.copytree(str(source), str(dest))
    else:
        dest = dest_dir / source.name
        shutil.copy2(str(source), str(dest))

    # Parse the lib table
    table_path = Path(config_dir) / type_config["table_file"]
    table = LibTable.parse_file(str(table_path))

    # Use forward slashes for KiCad compatibility
    uri = str(dest).replace("\\", "/")

    entry = LibEntry(
        name=lib_name,
        lib_type=type_config["kicad_type"],
        uri=uri,
        options="",
        descr=description,
    )

    if table.has_library(lib_name):
        return {
            "success": False,
            "error": f"Library '{lib_name}' already exists in {type_config['table_file']}",
            "_hint": "Choose a different libraryName, or call list_symbol_libraries / list_footprint_libraries to see existing entries.",
        }

    table.add_library(entry)
    table.write_file(str(table_path))

    return {
        "success": True,
        "output": f"Library '{lib_name}' installed to {dest} and registered in {type_config['table_file']}",
        "data": {
            "name": lib_name,
            "path": str(dest),
            "table": type_config["table_file"],
        },
        "_hint": (
            f"✅ Library '{lib_name}' is now registered. For next-time confidence, run "
            f"`kicad_lint_library '{{\"libraryPath\":\"<path>\"}}'` BEFORE install to "
            f"catch malformed files, outdated formats, or wrong-filetype-renamed-with-"
            f".kicad_sym surprises in ~100ms — much faster than discovering a broken "
            f"library inside the GUI later. Any KiCad windows already open need to be "
            f"closed + reopened to pick up the new library entry (sym-lib-table is read at startup)."
        ),
    }