from __future__ import annotations

import json
from pathlib import Path

from fivemghost_shared_client.registration import cli_registry
from fivemghost_shared_client.registration.claude_internal import (
    get_claude_internal_config_path,
    remove_claude_internal_config,
    upsert_claude_internal_config_data,
    write_claude_internal_config,
)
from fivemghost_shared_client.registration.gemini_internal import (
    get_gemini_internal_config_path,
    remove_gemini_internal_config,
    upsert_gemini_internal_config_data,
    write_gemini_internal_config,
)


def test_claude_internal_config_path_uses_internal_directory(tmp_path: Path) -> None:
    assert get_claude_internal_config_path(tmp_path) == tmp_path / ".claude-internal" / ".claude.json"


def test_gemini_internal_config_path_uses_shared_gemini_directory(tmp_path: Path) -> None:
    assert get_gemini_internal_config_path(tmp_path) == tmp_path / ".gemini" / "settings.internal.json"


def test_write_claude_internal_config_preserves_existing_data(tmp_path: Path) -> None:
    config_path = tmp_path / ".claude-internal" / ".claude.json"
    config_path.parent.mkdir(parents=True)
    config_path.write_text(json.dumps({"firstStartTime": "2026-04-14T00:00:00Z", "mcpServers": {"yt-mcp": {"type": "stdio"}}}))

    status = write_claude_internal_config(
        server_name="reddit-mcp",
        runtime="python3",
        launcher_path="/tmp/launcher.py",
        config_path=config_path,
    )

    data = json.loads(config_path.read_text())
    assert status == "updated"
    assert data["firstStartTime"] == "2026-04-14T00:00:00Z"
    assert data["mcpServers"]["reddit-mcp"]["command"] == "python3"
    assert data["mcpServers"]["reddit-mcp"]["args"] == ["/tmp/launcher.py", "serve"]
    assert data["mcpServers"]["reddit-mcp"]["type"] == "stdio"
    assert "yt-mcp" in data["mcpServers"]


def test_write_gemini_internal_config_preserves_existing_data(tmp_path: Path) -> None:
    config_path = tmp_path / ".gemini" / "settings.internal.json"
    config_path.parent.mkdir(parents=True)
    config_path.write_text(json.dumps({"security": {"auth": {"selectedType": "gongfeng"}}, "mcpServers": {"yt-mcp": {"command": "node"}}}))

    status = write_gemini_internal_config(
        server_name="reddit-mcp",
        runtime="python3",
        launcher_path="/tmp/launcher.py",
        config_path=config_path,
    )

    data = json.loads(config_path.read_text())
    assert status == "updated"
    assert data["security"]["auth"]["selectedType"] == "gongfeng"
    assert data["mcpServers"]["reddit-mcp"]["command"] == "python3"
    assert data["mcpServers"]["reddit-mcp"]["args"] == ["/tmp/launcher.py", "serve"]
    assert "yt-mcp" in data["mcpServers"]


def test_remove_claude_internal_config_only_removes_target_entry(tmp_path: Path) -> None:
    config_path = tmp_path / ".claude-internal" / ".claude.json"
    config_path.parent.mkdir(parents=True)
    config_path.write_text(
        json.dumps(
            upsert_claude_internal_config_data(
                {"mcpServers": {"yt-mcp": {"type": "stdio", "command": "node", "args": ["/tmp/yt", "serve"], "env": {}}}},
                "reddit-mcp",
                "python3",
                "/tmp/reddit",
            )
        )
    )

    status = remove_claude_internal_config(server_name="reddit-mcp", config_path=config_path)

    data = json.loads(config_path.read_text())
    assert status == "removed"
    assert "reddit-mcp" not in data["mcpServers"]
    assert "yt-mcp" in data["mcpServers"]


def test_remove_gemini_internal_config_only_removes_target_entry(tmp_path: Path) -> None:
    config_path = tmp_path / ".gemini" / "settings.internal.json"
    config_path.parent.mkdir(parents=True)
    config_path.write_text(
        json.dumps(
            upsert_gemini_internal_config_data(
                {"mcpServers": {"yt-mcp": {"command": "node", "args": ["/tmp/yt", "serve"]}}},
                "reddit-mcp",
                "python3",
                "/tmp/reddit",
            )
        )
    )

    status = remove_gemini_internal_config(server_name="reddit-mcp", config_path=config_path)

    data = json.loads(config_path.read_text())
    assert status == "removed"
    assert "reddit-mcp" not in data["mcpServers"]
    assert "yt-mcp" in data["mcpServers"]


def test_register_all_writes_internal_client_configs(monkeypatch) -> None:
    seen: list[tuple[str, str]] = []

    monkeypatch.setattr(cli_registry.shutil, "which", lambda _bin: None)
    monkeypatch.setattr(cli_registry, "write_claude_internal_config", lambda **_kwargs: seen.append(("register", "claude")) or "created")
    monkeypatch.setattr(cli_registry, "write_codex_internal_config", lambda **_kwargs: seen.append(("register", "codex")) or "created")
    monkeypatch.setattr(cli_registry, "write_gemini_internal_config", lambda **_kwargs: seen.append(("register", "gemini")) or "created")
    monkeypatch.setattr(cli_registry, "write_openclaw_config", lambda **_kwargs: seen.append(("register", "openclaw")) or "created")

    cli_registry.register_all(server_name="reddit-mcp", runtime="python3", launcher_path="/tmp/launcher.py")

    assert seen == [
        ("register", "claude"),
        ("register", "codex"),
        ("register", "gemini"),
        ("register", "openclaw"),
    ]


def test_unregister_all_removes_internal_client_configs(monkeypatch) -> None:
    seen: list[tuple[str, str]] = []

    monkeypatch.setattr(cli_registry.shutil, "which", lambda _bin: None)
    monkeypatch.setattr(cli_registry, "remove_claude_internal_config", lambda **_kwargs: seen.append(("remove", "claude")) or "removed")
    monkeypatch.setattr(cli_registry, "remove_codex_internal_config", lambda **_kwargs: seen.append(("remove", "codex")) or "removed")
    monkeypatch.setattr(cli_registry, "remove_gemini_internal_config", lambda **_kwargs: seen.append(("remove", "gemini")) or "removed")
    monkeypatch.setattr(cli_registry, "remove_openclaw_config", lambda **_kwargs: seen.append(("remove", "openclaw")) or "removed")

    cli_registry.unregister_all(server_name="reddit-mcp")

    assert seen == [
        ("remove", "claude"),
        ("remove", "codex"),
        ("remove", "gemini"),
        ("remove", "openclaw"),
    ]
