"""Tests for cli.py setup command and agent registry."""
from __future__ import annotations

import json
import sys
from pathlib import Path
from unittest.mock import patch

import pytest

from staso.cli import cmd_setup, cmd_setup_claude_code, _build_hooks_config, _merge_settings, CLAUDE_CODE, get_agent


class TestAgentRegistry:
    def test_claude_code_registered(self):
        agent = get_agent("claude-code")
        assert agent is not None
        assert agent.module == "claude_code"

    def test_unknown_agent_returns_none(self):
        assert get_agent("nonexistent") is None


class TestBuildHooksConfig:
    def test_all_events_present(self):
        hooks = _build_hooks_config("python3 -m staso.claude_code")
        expected_events = {
            "SessionStart", "UserPromptSubmit", "PreToolUse", "PostToolUse",
            "PostToolUseFailure", "Stop", "StopFailure", "SubagentStart",
            "SubagentStop", "SessionEnd",
        }
        assert set(hooks.keys()) == expected_events

    def test_uses_agent_config(self):
        hooks = _build_hooks_config("python3 -m staso.claude_code", agent=CLAUDE_CODE)
        assert set(hooks.keys()) == set(CLAUDE_CODE.hook_events)

    def test_tool_events_have_matcher(self):
        hooks = _build_hooks_config("python3 -m staso.claude_code")
        for event in ("PreToolUse", "PostToolUse", "PostToolUseFailure"):
            entry = hooks[event][0]
            assert "matcher" in entry

    def test_non_tool_events_no_matcher(self):
        hooks = _build_hooks_config("python3 -m staso.claude_code")
        for event in ("SessionStart", "Stop", "StopFailure", "SessionEnd"):
            entry = hooks[event][0]
            assert "matcher" not in entry

    def test_command_embedded(self):
        hooks = _build_hooks_config("/usr/bin/python3 -m staso.claude_code")
        entry = hooks["Stop"][0]
        cmd = entry["hooks"][0]["command"]
        assert "staso.claude_code" in cmd


class TestMergeSettings:
    def test_merges_into_empty(self):
        hooks = {"Stop": [{"hooks": [{"type": "command", "command": "python3 -m staso.claude_code"}]}]}
        env = {"STASO_API_KEY": "ak_test"}
        result = _merge_settings({}, hooks, env)
        assert result["hooks"]["Stop"][0]["hooks"][0]["command"] == "python3 -m staso.claude_code"
        assert result["env"]["STASO_API_KEY"] == "ak_test"

    def test_preserves_existing_non_staso_hooks(self):
        existing = {
            "hooks": {
                "Stop": [{"hooks": [{"type": "command", "command": "my-other-hook.sh"}]}]
            }
        }
        hooks = {"Stop": [{"hooks": [{"type": "command", "command": "python3 -m staso.claude_code"}]}]}
        result = _merge_settings(existing, hooks, {})
        stop_entries = result["hooks"]["Stop"]
        commands = [e["hooks"][0]["command"] for e in stop_entries]
        assert "my-other-hook.sh" in commands
        assert any("staso.claude_code" in c for c in commands)

    def test_replaces_existing_staso_entry(self):
        existing = {
            "hooks": {
                "Stop": [{"hooks": [{"type": "command", "command": "python3 -m staso.claude_code"}]}]
            }
        }
        hooks = {"Stop": [{"hooks": [{"type": "command", "command": "python3 -m staso.claude_code"}]}]}
        result = _merge_settings(existing, hooks, {})
        assert len(result["hooks"]["Stop"]) == 1

    def test_preserves_other_settings_keys(self):
        existing = {"model": "claude-opus-4-6", "theme": "dark"}
        result = _merge_settings(existing, {}, {})
        assert result["model"] == "claude-opus-4-6"
        assert result["theme"] == "dark"


class TestSetupCommand:
    def test_writes_global_settings(self, tmp_path, monkeypatch):
        settings_path = tmp_path / ".claude" / "settings.json"
        monkeypatch.setattr("staso.cli.Path.home", lambda: tmp_path)

        import argparse
        args = argparse.Namespace(
            target="claude-code",
            api_key="ak_testkey123",
            base_url="https://api.staso.dev",
            workspace="my-workspace",
            environment="production",
            agent_id="my-agent",
            scope="global",
        )

        with patch("staso.cli.sys.executable", "/usr/bin/python3"):
            result = cmd_setup(args)

        assert result == 0
        written = json.loads(settings_path.read_text())
        assert written["env"]["STASO_API_KEY"] == "ak_testkey123"
        assert written["env"]["STASO_BASE_URL"] == "https://api.staso.dev"
        assert written["env"]["STASO_WORKSPACE_SLUG"] == "my-workspace"
        assert "hooks" in written
        assert "Stop" in written["hooks"]

    def test_unknown_agent_returns_error(self):
        import argparse
        args = argparse.Namespace(
            target="nonexistent",
            api_key="ak_test",
            base_url=None,
            workspace=None,
            environment="production",
            agent_id=None,
            scope="global",
        )
        result = cmd_setup(args)
        assert result == 1

    def test_missing_api_key_returns_error(self, monkeypatch):
        monkeypatch.delenv("STASO_API_KEY", raising=False)
        import argparse
        args = argparse.Namespace(
            target="claude-code",
            api_key=None,
            base_url=None,
            workspace=None,
            environment="production",
            agent_id=None,
            scope="global",
        )
        result = cmd_setup(args)
        assert result == 1

    def test_api_key_from_env(self, tmp_path, monkeypatch):
        monkeypatch.setenv("STASO_API_KEY", "ak_from_env")
        monkeypatch.setattr("staso.cli.Path.home", lambda: tmp_path)
        (tmp_path / ".claude").mkdir()

        import argparse
        args = argparse.Namespace(
            target="claude-code",
            api_key=None,
            base_url=None,
            workspace=None,
            environment="production",
            agent_id=None,
            scope="global",
        )
        result = cmd_setup(args)
        assert result == 0
        written = json.loads((tmp_path / ".claude" / "settings.json").read_text())
        assert written["env"]["STASO_API_KEY"] == "ak_from_env"


class TestDeprecatedAlias:
    def test_setup_claude_code_delegates(self, tmp_path, monkeypatch):
        monkeypatch.setattr("staso.cli.Path.home", lambda: tmp_path)

        import argparse
        args = argparse.Namespace(
            api_key="ak_test",
            base_url=None,
            workspace=None,
            environment="production",
            agent_id=None,
            scope="global",
        )

        with patch("staso.cli.sys.executable", "/usr/bin/python3"):
            result = cmd_setup_claude_code(args)

        assert result == 0
        assert args.target == "claude-code"
