"""Core logic for the ``mld link`` and ``mld unlink`` commands."""

from __future__ import annotations

import argparse
import subprocess
import sys
from pathlib import Path


def cmd_link(args: argparse.Namespace) -> None:
    """Link local SDK source into all sibling plugin repos."""
    platform_root = _find_platform_root(Path.cwd())
    sdk_python_dir = platform_root / "packages" / "sdk-python"
    sdk_frontend_dir = platform_root / "packages" / "sdk-frontend"

    if getattr(args, "sdk_path", None):
        sdk_path = Path(args.sdk_path).resolve()
        sdk_python_dir = sdk_path / "packages" / "sdk-python"
        sdk_frontend_dir = sdk_path / "packages" / "sdk-frontend"

    root_dir = platform_root.parent

    print("Linking local SDK into sibling plugins")
    print(f"  Platform: {platform_root}")
    print(f"  Root:     {root_dir}")
    print()

    # Step 1: Register JS SDK globally
    print("-- Registering JS SDK globally --")
    _register_js_sdk(sdk_frontend_dir)
    print()

    # Step 2: Link into each plugin
    print("-- Linking plugins --")
    plugins = _find_sibling_plugins(platform_root)

    for plugin_dir in plugins:
        print(f"{plugin_dir.name}:")
        _link_plugin_python(plugin_dir, sdk_python_dir)
        _link_plugin_frontend(plugin_dir)
        print()

    if not plugins:
        print(f"[skip] No plugin directories found matching mld-* in {root_dir}")

    print(f"Done. {len(plugins)} plugin(s) processed.")


def cmd_unlink(args: argparse.Namespace) -> None:
    """Restore all sibling plugins to published SDK versions."""
    platform_root = _find_platform_root(Path.cwd())
    root_dir = platform_root.parent

    print("Restoring plugins to published SDK versions")
    print(f"  Platform: {platform_root}")
    print(f"  Root:     {root_dir}")
    print()

    print("-- Restoring plugins --")
    plugins = _find_sibling_plugins(platform_root)

    for plugin_dir in plugins:
        print(f"{plugin_dir.name}:")
        _unlink_plugin_python(plugin_dir)
        _unlink_plugin_frontend(plugin_dir)
        print()

    if not plugins:
        print(f"[skip] No plugin directories found matching mld-* in {root_dir}")

    print(f"Done. {len(plugins)} plugin(s) restored.")


def _find_platform_root(start: Path) -> Path:
    """Walk up from *start* looking for the platform root.

    The platform root is identified by the presence of
    ``packages/sdk-python/pyproject.toml``.
    """
    current = start.resolve()
    while True:
        if (current / "packages" / "sdk-python" / "pyproject.toml").exists():
            return current
        parent = current.parent
        if parent == current:
            print(
                "Error: could not find platform root "
                "(no packages/sdk-python/pyproject.toml in any ancestor).",
                file=sys.stderr,
            )
            sys.exit(1)
        current = parent


def _find_sibling_plugins(platform_dir: Path) -> list[Path]:
    """Find sibling ``mld-*`` directories that contain a ``pyproject.toml``."""
    root_dir = platform_dir.parent
    platform_resolved = platform_dir.resolve()
    plugins = sorted(
        d
        for d in root_dir.glob("mld-*")
        if d.is_dir()
        and d.resolve() != platform_resolved
        and (d / "pyproject.toml").exists()
    )
    return plugins


def _register_js_sdk(sdk_frontend_dir: Path) -> bool:
    """Register the JS SDK globally via ``bun link``."""
    if not (sdk_frontend_dir / "package.json").exists():
        print(f"[skip] JS SDK package.json not found at {sdk_frontend_dir}")
        return False

    result = subprocess.run(
        ["bun", "link"],
        cwd=sdk_frontend_dir,
        capture_output=True,
        text=True,
    )
    if result.returncode == 0:
        print("[ok] @morscherlab/mld-sdk registered globally")
        return True

    print(
        f"[warn] bun link failed (non-fatal): {result.stderr.strip()}",
        file=sys.stderr,
    )
    return False


def _link_plugin_python(plugin_dir: Path, sdk_python_dir: Path) -> bool:
    """Install the local SDK in editable mode into the plugin's venv."""
    if not (plugin_dir / ".venv").is_dir():
        print("  [skip] python: no .venv directory")
        return False

    result = subprocess.run(
        ["uv", "pip", "install", "-e", str(sdk_python_dir)],
        cwd=plugin_dir,
        capture_output=True,
        text=True,
    )
    if result.returncode == 0:
        print("  [ok] python: mld-sdk linked (editable)")
        return True

    print(
        f"  [warn] python: link failed: {result.stderr.strip()}",
        file=sys.stderr,
    )
    return False


def _link_plugin_frontend(plugin_dir: Path) -> bool:
    """Link the JS SDK into the plugin's frontend via ``bun link``."""
    if not (plugin_dir / "frontend" / "package.json").exists():
        print("  [skip] frontend: no frontend/package.json")
        return False

    result = subprocess.run(
        ["bun", "link", "@morscherlab/mld-sdk"],
        cwd=plugin_dir / "frontend",
        capture_output=True,
        text=True,
    )
    if result.returncode == 0:
        print("  [ok] frontend: @morscherlab/mld-sdk linked")
        return True

    print(
        f"  [warn] frontend: link failed: {result.stderr.strip()}",
        file=sys.stderr,
    )
    return False


def _unlink_plugin_python(plugin_dir: Path) -> bool:
    """Restore Python deps from pyproject.toml via ``uv sync``."""
    if not (plugin_dir / ".venv").is_dir():
        print("  [skip] python: no .venv directory")
        return False

    result = subprocess.run(
        ["uv", "sync"],
        cwd=plugin_dir,
        capture_output=True,
        text=True,
    )
    if result.returncode == 0:
        print("  [ok] python: restored from pyproject.toml")
        return True

    print(
        f"  [warn] python: restore failed: {result.stderr.strip()}",
        file=sys.stderr,
    )
    return False


def _unlink_plugin_frontend(plugin_dir: Path) -> bool:
    """Restore JS deps from package.json via ``bun install``."""
    if not (plugin_dir / "frontend" / "package.json").exists():
        print("  [skip] frontend: no frontend/package.json")
        return False

    result = subprocess.run(
        ["bun", "install"],
        cwd=plugin_dir / "frontend",
        capture_output=True,
        text=True,
    )
    if result.returncode == 0:
        print("  [ok] frontend: restored from package.json")
        return True

    print(
        f"  [warn] frontend: restore failed: {result.stderr.strip()}",
        file=sys.stderr,
    )
    return False
