"""Tests for the installer plugin system."""

import json
import tempfile
from pathlib import Path

import pytest

from teukhos.installers.base import (
    BaseInstaller,
    InstallScope,
    atomic_write_json,
    merge_mcp_entry,
    read_json_config,
    remove_mcp_entry,
)


def test_install_scope_values():
    assert InstallScope.global_.value == "global"
    assert InstallScope.project.value == "project"


def test_read_json_config_existing():
    with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
        json.dump({"mcpServers": {"existing": {}}}, f)
        path = Path(f.name)
    result = read_json_config(path)
    assert result == {"mcpServers": {"existing": {}}}


def test_read_json_config_missing():
    result = read_json_config(Path("/nonexistent/config.json"))
    assert result == {}


def test_read_json_config_malformed():
    with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
        f.write("{invalid json")
        path = Path(f.name)
    with pytest.raises(json.JSONDecodeError):
        read_json_config(path)


def test_atomic_write_json(tmp_path):
    target = tmp_path / "subdir" / "config.json"
    data = {"mcpServers": {"test": {"command": "echo"}}}
    atomic_write_json(target, data)
    assert target.exists()
    assert json.loads(target.read_text()) == data


def test_atomic_write_json_creates_backup(tmp_path):
    target = tmp_path / "config.json"
    target.write_text(json.dumps({"old": True}))
    atomic_write_json(target, {"new": True})
    backup = tmp_path / "config.json.teukhos-backup"
    assert backup.exists()
    assert json.loads(backup.read_text()) == {"old": True}


def test_merge_mcp_entry():
    existing = {"mcpServers": {"other-server": {"command": "other"}}}
    entry = {"command": "teukhos", "args": ["serve", "config.yaml"]}
    result = merge_mcp_entry(existing, "teukhos-test", entry, key="mcpServers")
    assert result["mcpServers"]["teukhos-test"] == entry
    assert result["mcpServers"]["other-server"] == {"command": "other"}


def test_merge_mcp_entry_creates_key():
    existing = {}
    entry = {"command": "teukhos"}
    result = merge_mcp_entry(existing, "teukhos-test", entry, key="mcpServers")
    assert result == {"mcpServers": {"teukhos-test": {"command": "teukhos"}}}


def test_remove_mcp_entry():
    config = {"mcpServers": {"a": {}, "b": {}}}
    result = remove_mcp_entry(config, "a")
    assert "a" not in result["mcpServers"]
    assert "b" in result["mcpServers"]


def test_base_installer_is_abstract():
    with pytest.raises(TypeError):
        BaseInstaller()


from teukhos.installers.claude_desktop import ClaudeDesktopInstaller


def test_claude_desktop_slug():
    installer = ClaudeDesktopInstaller()
    assert installer.slug == "claude-desktop"
    assert installer.name == "Claude Desktop"


def test_claude_desktop_no_project_scope():
    installer = ClaudeDesktopInstaller()
    assert InstallScope.project not in installer.supported_scopes


def test_claude_desktop_install_stdio(tmp_path):
    config_file = tmp_path / "claude_desktop_config.json"
    installer = ClaudeDesktopInstaller()
    installer._config_path_override = {InstallScope.global_: config_file}
    installer.install_stdio("teukhos-test", Path("/path/to/config.yaml"))
    data = json.loads(config_file.read_text())
    assert "teukhos-test" in data["mcpServers"]
    assert data["mcpServers"]["teukhos-test"]["args"] == ["serve", str(Path("/path/to/config.yaml"))]


def test_claude_desktop_install_http(tmp_path):
    config_file = tmp_path / "claude_desktop_config.json"
    installer = ClaudeDesktopInstaller()
    installer._config_path_override = {InstallScope.global_: config_file}
    installer.install_http("teukhos-test", "http://localhost:8765/mcp", "literal-key")
    data = json.loads(config_file.read_text())
    entry = data["mcpServers"]["teukhos-test"]
    assert entry["url"] == "http://localhost:8765/mcp"
    assert entry["headers"]["Authorization"] == "Bearer literal-key"


def test_claude_desktop_uninstall(tmp_path):
    config_file = tmp_path / "claude_desktop_config.json"
    config_file.write_text(json.dumps({
        "mcpServers": {"teukhos-test": {"command": "teukhos"}, "other": {"command": "other"}}
    }))
    installer = ClaudeDesktopInstaller()
    installer._config_path_override = {InstallScope.global_: config_file}
    installer.uninstall("teukhos-test")
    data = json.loads(config_file.read_text())
    assert "teukhos-test" not in data["mcpServers"]
    assert "other" in data["mcpServers"]


from teukhos.installers.claude_code import ClaudeCodeInstaller


def test_claude_code_slug():
    installer = ClaudeCodeInstaller()
    assert installer.slug == "claude-code"
    assert InstallScope.project in installer.supported_scopes


def test_claude_code_install_stdio(tmp_path):
    config_file = tmp_path / ".claude.json"
    installer = ClaudeCodeInstaller()
    installer._config_path_override = {InstallScope.global_: config_file}
    installer.install_stdio("teukhos-test", Path("/path/to/config.yaml"))
    data = json.loads(config_file.read_text())
    assert "teukhos-test" in data["mcpServers"]


def test_claude_code_install_http_env_substitution(tmp_path):
    config_file = tmp_path / ".claude.json"
    installer = ClaudeCodeInstaller()
    installer._config_path_override = {InstallScope.global_: config_file}
    installer.install_http("teukhos-test", "http://host:8765/mcp", "env:TEUKHOS_API_KEY")
    data = json.loads(config_file.read_text())
    entry = data["mcpServers"]["teukhos-test"]
    assert entry["url"] == "http://host:8765/mcp"
    assert "${TEUKHOS_API_KEY}" in entry["headers"]["Authorization"]


def test_claude_code_project_scope(tmp_path):
    config_file = tmp_path / ".claude" / "settings.json"
    installer = ClaudeCodeInstaller(cwd=tmp_path)
    installer._config_path_override = {InstallScope.project: config_file}
    installer.install_stdio("teukhos-test", Path("/path/to/config.yaml"), scope=InstallScope.project)
    data = json.loads(config_file.read_text())
    assert "teukhos-test" in data["mcpServers"]


from teukhos.installers.cursor import CursorInstaller


def test_cursor_slug():
    installer = CursorInstaller()
    assert installer.slug == "cursor"
    assert InstallScope.project in installer.supported_scopes


def test_cursor_install_stdio(tmp_path):
    config_file = tmp_path / "mcp.json"
    installer = CursorInstaller()
    installer._config_path_override = {InstallScope.global_: config_file}
    installer.install_stdio("teukhos-test", Path("/path/to/config.yaml"))
    data = json.loads(config_file.read_text())
    assert "teukhos-test" in data["mcpServers"]


from teukhos.installers.github_copilot import GitHubCopilotInstaller


def test_github_copilot_slug():
    installer = GitHubCopilotInstaller()
    assert installer.slug == "github-copilot"


def test_github_copilot_uses_servers_key(tmp_path):
    config_file = tmp_path / "mcp.json"
    installer = GitHubCopilotInstaller()
    installer._config_path_override = {InstallScope.global_: config_file}
    installer.install_stdio("teukhos-test", Path("/path/to/config.yaml"))
    data = json.loads(config_file.read_text())
    assert "servers" in data
    entry = data["servers"]["teukhos-test"]
    assert entry["type"] == "stdio"


def test_github_copilot_http_has_type(tmp_path):
    config_file = tmp_path / "mcp.json"
    installer = GitHubCopilotInstaller()
    installer._config_path_override = {InstallScope.global_: config_file}
    installer.install_http("teukhos-test", "http://host:8765/mcp", None)
    data = json.loads(config_file.read_text())
    entry = data["servers"]["teukhos-test"]
    assert entry["type"] == "http"
    assert entry["url"] == "http://host:8765/mcp"


from teukhos.installers.gemini_cli import GeminiCLIInstaller
from teukhos.installers.codex import CodexInstaller


def test_gemini_cli_slug():
    installer = GeminiCLIInstaller()
    assert installer.slug == "gemini-cli"
    assert InstallScope.project not in installer.supported_scopes


def test_gemini_cli_install_stdio(tmp_path):
    config_file = tmp_path / "settings.json"
    installer = GeminiCLIInstaller()
    installer._config_path_override = {InstallScope.global_: config_file}
    installer.install_stdio("teukhos-test", Path("/path/to/config.yaml"))
    data = json.loads(config_file.read_text())
    assert "teukhos-test" in data["mcpServers"]


def test_codex_slug():
    installer = CodexInstaller()
    assert installer.slug == "codex"
    assert InstallScope.project not in installer.supported_scopes


def test_codex_install_stdio(tmp_path):
    config_file = tmp_path / "config.json"
    installer = CodexInstaller()
    installer._config_path_override = {InstallScope.global_: config_file}
    installer.install_stdio("teukhos-test", Path("/path/to/config.yaml"))
    data = json.loads(config_file.read_text())
    assert "teukhos-test" in data["mcpServers"]


# --- Tier 2 installers ---

from teukhos.installers.windsurf import WindsurfInstaller


def test_windsurf_slug():
    installer = WindsurfInstaller()
    assert installer.slug == "windsurf"
    assert installer.name == "Windsurf"


def test_windsurf_install_stdio(tmp_path):
    config_file = tmp_path / "mcp_config.json"
    installer = WindsurfInstaller()
    installer._config_path_override = {InstallScope.global_: config_file}
    installer.install_stdio("teukhos-test", Path("/path/to/config.yaml"))
    data = json.loads(config_file.read_text())
    assert "teukhos-test" in data["mcpServers"]


from teukhos.installers.roo_code import RooCodeInstaller


def test_roo_code_slug():
    installer = RooCodeInstaller()
    assert installer.slug == "roo-code"
    assert installer.name == "Roo Code"


def test_roo_code_install_stdio(tmp_path):
    config_file = tmp_path / "mcp.json"
    installer = RooCodeInstaller()
    installer._config_path_override = {InstallScope.global_: config_file}
    installer.install_stdio("teukhos-test", Path("/path/to/config.yaml"))
    data = json.loads(config_file.read_text())
    assert "teukhos-test" in data["mcpServers"]


from teukhos.installers.continue_dev import ContinueDevInstaller


def test_continue_dev_slug():
    installer = ContinueDevInstaller()
    assert installer.slug == "continue"
    assert installer.name == "Continue.dev"


def test_continue_dev_install_stdio(tmp_path):
    config_file = tmp_path / "config.json"
    installer = ContinueDevInstaller()
    installer._config_path_override = {InstallScope.global_: config_file}
    installer.install_stdio("teukhos-test", Path("/path/to/config.yaml"))
    data = json.loads(config_file.read_text())
    assert "teukhos-test" in data["mcpServers"]


from teukhos.installers.kiro import KiroInstaller


def test_kiro_slug():
    installer = KiroInstaller()
    assert installer.slug == "kiro"
    assert installer.name == "Kiro"


def test_kiro_install_stdio(tmp_path):
    config_file = tmp_path / "settings.json"
    installer = KiroInstaller()
    installer._config_path_override = {InstallScope.global_: config_file}
    installer.install_stdio("teukhos-test", Path("/path/to/config.yaml"))
    data = json.loads(config_file.read_text())
    assert "teukhos-test" in data["mcpServers"]


from teukhos.installers.auggie import AuggieInstaller


def test_auggie_slug():
    installer = AuggieInstaller()
    assert installer.slug == "auggie"
    assert installer.name == "Auggie"


def test_auggie_install_stdio(tmp_path):
    config_file = tmp_path / "mcp.json"
    installer = AuggieInstaller()
    installer._config_path_override = {InstallScope.global_: config_file}
    installer.install_stdio("teukhos-test", Path("/path/to/config.yaml"))
    data = json.loads(config_file.read_text())
    assert "teukhos-test" in data["mcpServers"]


from teukhos.installers.codebuddy import CodeBuddyInstaller


def test_codebuddy_slug():
    installer = CodeBuddyInstaller()
    assert installer.slug == "codebuddy"
    assert installer.name == "CodeBuddy"


def test_codebuddy_install_stdio(tmp_path):
    config_file = tmp_path / "mcp.json"
    installer = CodeBuddyInstaller()
    installer._config_path_override = {InstallScope.global_: config_file}
    installer.install_stdio("teukhos-test", Path("/path/to/config.yaml"))
    data = json.loads(config_file.read_text())
    assert "teukhos-test" in data["mcpServers"]


from teukhos.installers.opencode import OpenCodeInstaller


def test_opencode_slug():
    installer = OpenCodeInstaller()
    assert installer.slug == "opencode"
    assert installer.name == "OpenCode"


def test_opencode_install_stdio(tmp_path):
    config_file = tmp_path / "config.json"
    installer = OpenCodeInstaller()
    installer._config_path_override = {InstallScope.global_: config_file}
    installer.install_stdio("teukhos-test", Path("/path/to/config.yaml"))
    data = json.loads(config_file.read_text())
    assert "teukhos-test" in data["mcpServers"]


from teukhos.installers.trae import TraeInstaller


def test_trae_slug():
    installer = TraeInstaller()
    assert installer.slug == "trae"
    assert installer.name == "Trae"


def test_trae_install_stdio(tmp_path):
    config_file = tmp_path / "mcp.json"
    installer = TraeInstaller()
    installer._config_path_override = {InstallScope.global_: config_file}
    installer.install_stdio("teukhos-test", Path("/path/to/config.yaml"))
    data = json.loads(config_file.read_text())
    assert "teukhos-test" in data["mcpServers"]


from teukhos.installers.cline import ClineInstaller


def test_cline_slug():
    installer = ClineInstaller()
    assert installer.slug == "cline"
    assert installer.name == "Cline"


def test_cline_install_stdio(tmp_path):
    config_file = tmp_path / "mcp.json"
    installer = ClineInstaller()
    installer._config_path_override = {InstallScope.global_: config_file}
    installer.install_stdio("teukhos-test", Path("/path/to/config.yaml"))
    data = json.loads(config_file.read_text())
    assert "teukhos-test" in data["mcpServers"]


# --- Registry tests ---

from teukhos.installers import (
    ALL_INSTALLERS,
    discover_clients,
    get_all_installers,
    get_installer,
)


def test_all_installers_have_unique_slugs():
    slugs = [cls.slug for cls in ALL_INSTALLERS]
    assert len(slugs) == len(set(slugs)), f"Duplicate slugs: {slugs}"


def test_all_installers_count():
    assert len(ALL_INSTALLERS) == 15


def test_get_installer_by_slug():
    inst = get_installer("cursor")
    assert inst is not None
    assert inst.name == "Cursor"


def test_get_installer_unknown():
    assert get_installer("nonexistent") is None


def test_get_all_installers():
    installers = get_all_installers()
    assert len(installers) == 15
    assert all(isinstance(i, BaseInstaller) for i in installers)


def test_discover_clients_returns_list():
    """discover_clients should return a list (may be empty in test env)."""
    result = discover_clients()
    assert isinstance(result, list)
