"""CLI registry orchestration for MCP registration across all supported clients."""

from __future__ import annotations

import shutil
import subprocess
from pathlib import Path

from .claude_internal import get_claude_internal_config_path, write_claude_internal_config, remove_claude_internal_config
from .codex_internal import get_codex_internal_config_path, write_codex_internal_config, remove_codex_internal_config
from .gemini_internal import get_gemini_internal_config_path, write_gemini_internal_config, remove_gemini_internal_config
from .openclaw import get_openclaw_config_path, write_openclaw_config, remove_openclaw_config


class RegistrationFailure(RuntimeError):
    """Raised when required MCP registration does not produce a usable client config."""


def _canonical_command_text(command: str, args: list[str]) -> str:
    return " ".join([command, *args]).strip()


def _looks_installed(config_path) -> bool:
    return config_path.exists() or config_path.parent.exists()


def _client_config_path(client: str) -> Path:
    if client == "claude":
        return get_claude_internal_config_path()
    if client == "codex":
        return get_codex_internal_config_path()
    if client == "gemini":
        return get_gemini_internal_config_path()
    if client == "openclaw":
        return get_openclaw_config_path()
    raise ValueError(f"Unknown client: {client}")


def _manual_registration_hint(client: str, command: str, args: list[str]) -> str:
    command_text = _canonical_command_text(command, args)
    config_path = _client_config_path(client)
    return (
        f"target_client={client} "
        f"config_path={config_path} "
        f"manual_command='{command_text}'"
    )


def _detected_clients() -> list[str]:
    detected: list[str] = []
    if _looks_installed(get_claude_internal_config_path()):
        detected.append("claude")
    if _looks_installed(get_codex_internal_config_path()):
        detected.append("codex")
    if _looks_installed(get_gemini_internal_config_path()):
        detected.append("gemini")
    if _looks_installed(get_openclaw_config_path()):
        detected.append("openclaw")
    return detected


def register_all(
    *,
    server_name: str,
    command: str,
    args: list[str],
) -> None:
    """Register MCP server with all detected CLIs.
    """
    detected_clients = _detected_clients()
    command_text = _canonical_command_text(command, args)
    if not detected_clients:
        raise RegistrationFailure(
            "No supported AI client detected for MCP registration. "
            f"Configure a supported client manually with `{command_text}`."
        )

    failures: list[str] = []
    for client in detected_clients:
        try:
            if client == "claude":
                status = write_claude_internal_config(server_name=server_name, command=command, args=args)
                print(f"\n🔗 Registering with Claude Code (internal)...")
                print(f"   ✅ Registered with Claude Code (internal) ({status} local config)")
            elif client == "codex":
                status = write_codex_internal_config(server_name=server_name, command=command, args=args)
                print(f"\n🔗 Registering with Codex CLI (internal)...")
                print(f"   ✅ Registered with Codex CLI (internal) ({status} local config)")
            elif client == "gemini":
                status = write_gemini_internal_config(server_name=server_name, command=command, args=args)
                print(f"\n🔗 Registering with Gemini CLI (internal)...")
                print(f"   ✅ Registered with Gemini CLI (internal) ({status} local config)")
            elif client == "openclaw":
                status = write_openclaw_config(server_name=server_name, command=command, args=args)
                print(f"\n🔗 Registering with OpenClaw...")
                print(f"   ✅ Registered with OpenClaw ({status} mcporter.json)")
        except Exception as exc:
            failures.append(
                f"{client}: registration failed. {_manual_registration_hint(client, command, args)}. Details: {exc}"
            )

    if failures:
        raise RegistrationFailure("\n".join(failures))


def unregister_all(*, server_name: str) -> None:
    """Remove MCP server registration from all detected CLIs.
    
    Args:
        server_name: Server name to unregister
    """
    print("\n🧹 Uninstalling MCP registrations\n")
    print("Removing MCP client registrations...")

    cli_candidates = [
        ("claude-internal", "Claude Code (internal)", ["claude-internal", "mcp", "remove", "-s", "user", server_name]),
        ("claude", "Claude Code", ["claude", "mcp", "remove", "-s", "user", server_name]),
        ("codex", "Codex CLI / Codex App", ["codex", "mcp", "remove", server_name]),
        ("gemini-internal", "Gemini CLI (internal)", ["gemini-internal", "mcp", "remove", "-s", "user", server_name]),
        ("gemini", "Gemini CLI", ["gemini", "mcp", "remove", "-s", "user", server_name]),
        ("opencode", "OpenCode", ["opencode", "mcp", "remove", server_name]),
    ]

    for binary, label, command in cli_candidates:
        if shutil.which(binary):
            try:
                result = subprocess.run(command, capture_output=True, text=True, timeout=15)
                if result.returncode == 0:
                    print(f"  ✅ Removed MCP registration from {label}")
                else:
                    stderr = (result.stderr or "").lower()
                    if any(text in stderr for text in ("not found", "no server", "unknown")):
                        print(f"  ℹ️  {label} did not have {server_name} registered")
                    else:
                        print(f"  ⚠️  Failed to remove MCP registration from {label}")
            except (OSError, subprocess.SubprocessError):
                print(f"  ⚠️  Failed to remove MCP registration from {label}")

    # codex-internal: direct TOML removal
    status = remove_claude_internal_config(server_name=server_name)
    if status == "removed":
        print(f"  ✅ Removed MCP registration from Claude Code (internal)")
    else:
        print(f"  ℹ️  Claude Code (internal) did not have {server_name} registered")

    try:
        remove_codex_internal_config(server_name=server_name)
        print(f"  ✅ Removed MCP registration from Codex CLI (internal)")
    except Exception:
        print(f"  ℹ️  Codex CLI (internal) did not have {server_name} registered")

    status = remove_gemini_internal_config(server_name=server_name)
    if status == "removed":
        print(f"  ✅ Removed MCP registration from Gemini CLI (internal)")
    else:
        print(f"  ℹ️  Gemini CLI (internal) did not have {server_name} registered")

    # openclaw: JSON removal
    status = remove_openclaw_config(server_name=server_name)
    if status == "removed":
        print(f"  ✅ Removed MCP registration from OpenClaw")
    else:
        print(f"  ℹ️  OpenClaw did not have {server_name} registered")
