"""Tests for Pydantic AI agent module."""

from unittest.mock import MagicMock, patch

from autodebug.agent import tools
from autodebug.agent.core import HikaflowDeps, get_supported_models
from autodebug.agent.system_prompt import HIKAFLOW_SYSTEM_PROMPT


class TestHikaflowDeps:
    """Test HikaflowDeps dataclass."""

    def test_required_fields(self):
        """Test required fields are enforced."""
        deps = HikaflowDeps(
            api_base="https://api.example.com",
            token="test-token",
            project_path="/path/to/project",
        )

        assert deps.api_base == "https://api.example.com"
        assert deps.token == "test-token"
        assert deps.project_path == "/path/to/project"

    def test_optional_fields_default(self):
        """Test optional fields have defaults."""
        deps = HikaflowDeps(
            api_base="https://api.example.com",
            token="test-token",
            project_path="/path/to/project",
        )

        assert deps.environment is None

    def test_github_token_from_env(self, monkeypatch):
        """Test github_token defaults from environment."""
        monkeypatch.setenv("GITHUB_TOKEN", "gh_test_token")

        deps = HikaflowDeps(
            api_base="https://api.example.com",
            token="test-token",
            project_path="/path/to/project",
        )

        assert deps.github_token == "gh_test_token"


class TestSystemPrompt:
    """Test system prompt content."""

    def test_prompt_mentions_hikaflow(self):
        """Test prompt identifies as Hikaflow."""
        assert "Hikaflow" in HIKAFLOW_SYSTEM_PROMPT

    def test_prompt_has_skill_menu_placeholder(self):
        """Test prompt has placeholder for progressive skill loading."""
        assert "{skill_menu}" in HIKAFLOW_SYSTEM_PROMPT

    def test_prompt_describes_capabilities(self):
        """Test prompt describes available capabilities."""
        assert "fetch" in HIKAFLOW_SYSTEM_PROMPT.lower()
        assert "replay" in HIKAFLOW_SYSTEM_PROMPT.lower()
        assert "transcript" in HIKAFLOW_SYSTEM_PROMPT.lower()

    def test_prompt_describes_tools(self):
        """Test prompt describes available tools across mode prompts."""
        from autodebug.agent.system_prompt import HIKAFLOW_SCAN_PROMPT
        assert "scan_for_bugs" in HIKAFLOW_SCAN_PROMPT
        assert "read_file" in HIKAFLOW_SYSTEM_PROMPT
        assert "review_files" in HIKAFLOW_SYSTEM_PROMPT


class TestGetSupportedModels:
    """Test get_supported_models function."""

    def test_returns_list(self):
        """Test returns a list of models."""
        models = get_supported_models()
        assert isinstance(models, list)
        assert len(models) > 0

    def test_model_has_required_keys(self):
        """Test each model has required keys."""
        models = get_supported_models()
        for model in models:
            assert "id" in model
            assert "name" in model
            assert "provider" in model

    def test_includes_openai_models(self):
        """Test includes OpenAI models."""
        models = get_supported_models()
        openai_models = [m for m in models if m["provider"] == "OpenAI"]
        assert len(openai_models) > 0

    def test_includes_anthropic_models(self):
        """Test includes Anthropic models."""
        models = get_supported_models()
        anthropic_models = [m for m in models if m["provider"] == "Anthropic"]
        assert len(anthropic_models) > 0

    def test_includes_ollama_models(self):
        """Test includes local Ollama models."""
        models = get_supported_models()
        ollama_models = [m for m in models if "Ollama" in m["provider"]]
        assert len(ollama_models) > 0


class TestToolFormatters:
    """Test tool output formatters."""

    def test_format_errors_table_empty(self):
        """Test formatting empty error list."""
        result = tools._format_errors_table([])
        assert "No errors found" in result

    def test_format_errors_table_with_data(self):
        """Test formatting error list with data."""
        errors = [
            {
                "id": "err_123",
                "exception_type": "KeyError",
                "message": "missing key",
                "count": 5,
                "last_seen": "2024-01-28",
            }
        ]
        result = tools._format_errors_table(errors)
        assert "err_123" in result
        assert "KeyError" in result
        assert "5" in result

    def test_format_error_details(self):
        """Test formatting error details."""
        error = {
            "exception_type": "ValueError",
            "message": "invalid value",
            "file": "app.py",
            "line": 42,
            "first_seen": "2024-01-01",
            "count": 10,
            "environment": "production",
            "stack_trace": "Traceback...",
        }
        transcript = {"http": [1, 2], "sql": [1], "time": []}

        result = tools._format_error_details(error, transcript)
        assert "ValueError" in result
        assert "app.py:42" in result
        assert "HTTP calls: 2" in result
        assert "SQL queries: 1" in result

    def test_format_replay_results_all_pass(self):
        """Test formatting when all replay runs pass."""
        results = [
            {"reproduced": True},
            {"reproduced": True},
            {"reproduced": True},
        ]
        result = tools._format_replay_results(results)
        assert "3/3" in result
        assert "reproduced" in result.lower()

    def test_format_replay_results_partial(self):
        """Test formatting when some runs fail."""
        results = [
            {"reproduced": True},
            {"reproduced": False},
            {"reproduced": True},
        ]
        result = tools._format_replay_results(results)
        assert "2/3" in result

    def test_format_transcript_http(self):
        """Test formatting HTTP transcript."""
        transcript = {
            "http": [
                {"method": "GET", "url": "https://api.example.com", "status": 200}
            ],
            "sql": [],
            "time": [],
        }
        result = tools._format_transcript(transcript, "http")
        assert "GET" in result
        assert "api.example.com" in result
        assert "200" in result

    def test_format_transcript_sql(self):
        """Test formatting SQL transcript."""
        transcript = {
            "http": [],
            "sql": [
                {"query": "SELECT * FROM users WHERE id = 1", "row_count": 1}
            ],
            "time": [],
        }
        result = tools._format_transcript(transcript, "sql")
        assert "SELECT" in result
        assert "1 rows" in result

    def test_format_hypotheses_empty(self):
        """Test formatting empty hypotheses."""
        result = tools._format_hypotheses([])
        assert "No fix hypotheses" in result

    def test_format_hypotheses_with_data(self):
        """Test formatting hypotheses with data."""
        hypotheses = [
            {
                "strategy": "Add null check",
                "confidence": 0.85,
                "root_cause": "Unhandled None value",
                "diff": "--- a/app.py\n+++ b/app.py",
            }
        ]
        result = tools._format_hypotheses(hypotheses)
        assert "Add null check" in result
        assert "85%" in result
        assert "Unhandled None" in result

    def test_format_validation_result_proven(self):
        """Test formatting proven fix validation."""
        result_data = {
            "verdict": "PROVEN_FIX",
            "passed": 10,
            "total": 10,
            "certificate_id": "cert_123",
        }
        result = tools._format_validation_result(result_data)
        assert "PROVEN" in result
        assert "10/10" in result
        assert "cert_123" in result

    def test_format_validation_result_flaky(self):
        """Test formatting flaky fix validation."""
        result_data = {
            "verdict": "FLAKY_FIX",
            "passed": 7,
            "total": 10,
        }
        result = tools._format_validation_result(result_data)
        assert "FLAKY" in result
        assert "7/10" in result

    def test_format_similar_fixes_empty(self):
        """Test formatting no similar fixes."""
        result = tools._format_similar_fixes([])
        assert "No similar fixes" in result

    def test_format_similar_fixes_with_data(self):
        """Test formatting similar fixes."""
        matches = [
            {
                "exception_type": "KeyError",
                "fix_type": "add null check",
                "success_rate": 0.9,
            }
        ]
        result = tools._format_similar_fixes(matches)
        assert "KeyError" in result
        assert "90%" in result


class TestCreateAgent:
    """Test agent creation."""

    @patch("pydantic_ai.Agent")
    def test_create_agent_default_model(self, mock_agent_class, monkeypatch):
        """Test agent creation with default model."""
        monkeypatch.delenv("HIKAFLOW_MODEL", raising=False)
        # Mock the tool decorator to avoid registration issues
        mock_agent_class.return_value.tool = MagicMock(return_value=lambda f: f)

        from autodebug.agent.core import create_agent
        agent = create_agent()

        mock_agent_class.assert_called_once()
        call_args = mock_agent_class.call_args
        # First positional arg should be the model
        assert call_args[0][0] == "openai:gpt-5"

    @patch("pydantic_ai.Agent")
    def test_create_agent_custom_model(self, mock_agent_class):
        """Test agent creation with custom model."""
        mock_agent_class.return_value.tool = MagicMock(return_value=lambda f: f)

        from autodebug.agent.core import create_agent
        agent = create_agent("anthropic:claude-sonnet-4")

        mock_agent_class.assert_called_once()
        call_args = mock_agent_class.call_args
        assert call_args[0][0] == "anthropic:claude-sonnet-4"

    @patch("pydantic_ai.Agent")
    def test_create_agent_from_env(self, mock_agent_class, monkeypatch):
        """Test agent creation from environment variable."""
        monkeypatch.setenv("HIKAFLOW_MODEL", "ollama:llama3.2")
        mock_agent_class.return_value.tool = MagicMock(return_value=lambda f: f)

        from autodebug.agent.core import create_agent
        agent = create_agent()

        mock_agent_class.assert_called_once()
        call_args = mock_agent_class.call_args
        assert call_args[0][0] == "ollama:llama3.2"
