"""OpenClaw dual-path registration — ported from yt-mcp's openClaw.ts."""

from __future__ import annotations

import json
import subprocess
from pathlib import Path


def get_openclaw_config_path(home_dir: Path | str | None = None) -> Path:
    """Return the OpenClaw mcporter config path."""
    if home_dir is None:
        home_dir = Path.home()
    else:
        home_dir = Path(home_dir)
    return home_dir / ".openclaw" / "workspace" / "config" / "mcporter.json"


def get_openclaw_skills_dir(home_dir: Path | str | None = None) -> Path:
    """Return the OpenClaw skills directory."""
    if home_dir is None:
        home_dir = Path.home()
    else:
        home_dir = Path(home_dir)
    return home_dir / ".openclaw" / "skills"


def _build_openclaw_server_config(
    command: str,
    args: list[str],
) -> dict:
    """Build an OpenClaw server config object."""
    return {
        "transport": "stdio",
        "command": command,
        "args": args,
    }


def _parse_openclaw_config(raw: str) -> dict:
    """Parse OpenClaw JSON config."""
    parsed = json.loads(raw)
    if not isinstance(parsed, dict):
        raise ValueError("OpenClaw config must be a JSON object")
    return parsed


def upsert_openclaw_config_text(
    current_text: str | None,
    server_name: str,
    command: str,
    args: list[str],
) -> str:
    """Upsert a server entry in OpenClaw config JSON text."""
    config = _parse_openclaw_config(current_text) if current_text else {}
    servers = config.get("servers", {})
    if not isinstance(servers, dict):
        servers = {}
    
    servers[server_name] = _build_openclaw_server_config(command, args)
    
    next_config = {**config, "servers": servers}
    return json.dumps(next_config, indent=2)


def remove_openclaw_config_entry_text(
    current_text: str | None,
    server_name: str,
) -> dict[str, str | bool | None]:
    """Remove a server entry from OpenClaw config JSON text."""
    if not current_text:
        return {"changed": False, "next_text": None}

    config = _parse_openclaw_config(current_text)
    servers = config.get("servers", {})
    
    if not isinstance(servers, dict) or server_name not in servers:
        return {"changed": False, "next_text": current_text}

    next_servers = dict(servers)
    del next_servers[server_name]

    next_config = dict(config)
    if next_servers:
        next_config["servers"] = next_servers
        next_text = json.dumps(next_config, indent=2)
    else:
        next_config.pop("servers", None)
        next_text = json.dumps(next_config, indent=2) if next_config else None

    return {"changed": True, "next_text": next_text}


def _is_openclaw_likely_installed(config_path: Path) -> bool:
    """Check if OpenClaw is likely installed."""
    # Check for mcporter or openclaw binary
    for binary in ("mcporter", "openclaw"):
        try:
            result = subprocess.run(
                [binary, "--version"],
                capture_output=True,
                text=True,
                timeout=10,
            )
            if result.returncode == 0:
                return True
        except (OSError, subprocess.SubprocessError):
            pass
    
    # Check for config path or parent directory
    return config_path.exists() or config_path.parent.exists()


def _try_mcporter_cli(
    server_name: str,
    command: str,
    args: list[str],
) -> bool:
    """Try to register via mcporter CLI. Returns True if successful."""
    try:
        command_args = [
            "mcporter",
            "config",
            "add",
            server_name,
            "--command",
            command,
        ]
        for arg in args:
            command_args.extend(["--arg", arg])
        result = subprocess.run(
            command_args,
            capture_output=True,
            text=True,
            timeout=15,
        )
        return result.returncode == 0
    except (OSError, subprocess.SubprocessError):
        return False


def write_openclaw_config(
    *,
    server_name: str,
    command: str,
    args: list[str],
    config_path: Path | str | None = None,
) -> str:
    """Write OpenClaw MCP config (try mcporter CLI, fallback to JSON).
    
    Returns:
        "created" or "updated"
    """
    if config_path is None:
        config_path = get_openclaw_config_path()
    else:
        config_path = Path(config_path)

    # Try mcporter CLI first
    if _try_mcporter_cli(server_name, command, args):
        # Determine if it was created or updated
        existing_text = config_path.read_text("utf-8") if config_path.exists() else None
        return "created" if existing_text is None else "updated"

    # Fallback: direct JSON write
    existing_text = config_path.read_text("utf-8") if config_path.exists() else None
    created = existing_text is None
    next_text = upsert_openclaw_config_text(existing_text, server_name, command, args)

    config_path.parent.mkdir(parents=True, exist_ok=True)
    config_path.write_text(f"{next_text}\n", "utf-8")

    return "created" if created else "updated"


def remove_openclaw_config(
    *,
    server_name: str,
    config_path: Path | str | None = None,
) -> str:
    """Remove OpenClaw MCP config entry.
    
    Returns:
        "removed" or "missing"
    """
    if config_path is None:
        config_path = get_openclaw_config_path()
    else:
        config_path = Path(config_path)

    existing_text = config_path.read_text("utf-8") if config_path.exists() else None
    result = remove_openclaw_config_entry_text(existing_text, server_name)

    if not result["changed"]:
        return "missing"

    next_text = result["next_text"]
    if next_text is None:
        config_path.unlink(missing_ok=True)
    else:
        config_path.parent.mkdir(parents=True, exist_ok=True)
        config_path.write_text(f"{next_text}\n", "utf-8")

    return "removed"
