"""
Unit tests for classification.py.

The Anthropic client is mocked at the boundary.

NOTE: Classification quality is not tested here — we verify only
that the function handles responses correctly and fails fast on
bad inputs and malformed responses. Integration tests cover
real classification quality.
"""

from __future__ import annotations

import json
from unittest.mock import MagicMock, patch

import pytest

from active_claude_github_mcp.classification import (
    ClassificationError,
    classify_turn,
    detect_theme_change,
)


API_KEY = "sk-ant-test-key"


def _mock_haiku(response_text: str):
    """Mock the Anthropic client to return a fixed response."""
    mock_client = MagicMock()
    mock_message = MagicMock()
    mock_message.content = [MagicMock(text=response_text)]
    mock_client.messages.create.return_value = mock_message
    return mock_client


VALID_CLASSIFY_RESPONSE = json.dumps({
    "destination": "discussion",
    "category": "Architecture",
    "issue_label": None,
    "suggested_title": "Auth token refresh strategy",
    "confidence": "high",
})

VALID_THEME_RESPONSE = json.dumps({
    "theme_changed": True,
    "confidence": "high",
    "fork_point_comment_id": "DC_abc123",
    "original_theme": "Auth tokens",
    "new_theme": "Database schema",
    "suggested_title": "Database schema design",
})


class TestClassifyTurn:
    def test_success_discussion(self):
        with patch(
            "active_claude_github_mcp.classification.anthropic.Anthropic",
            return_value=_mock_haiku(VALID_CLASSIFY_RESPONSE),
        ):
            result = classify_turn(API_KEY, "How should we handle auth tokens?")
        assert result.destination == "discussion"
        assert result.category == "Architecture"
        assert result.confidence == "high"

    def test_success_issue(self):
        issue_response = json.dumps({
            "destination": "issue",
            "category": None,
            "issue_label": "bug",
            "suggested_title": "Login button throws 500 error",
            "confidence": "high",
        })
        with patch(
            "active_claude_github_mcp.classification.anthropic.Anthropic",
            return_value=_mock_haiku(issue_response),
        ):
            result = classify_turn(API_KEY, "The login button crashes the server.")
        assert result.destination == "issue"
        assert result.issue_label == "bug"

    def test_empty_text_raises(self):
        with pytest.raises(ValueError, match="text"):
            classify_turn(API_KEY, "")

    def test_invalid_json_response_raises(self):
        with patch(
            "active_claude_github_mcp.classification.anthropic.Anthropic",
            return_value=_mock_haiku("this is not json"),
        ):
            with pytest.raises(ClassificationError, match="not valid JSON"):
                classify_turn(API_KEY, "some message")

    def test_invalid_schema_response_raises(self):
        bad_response = json.dumps({"destination": "unknown_value"})
        with patch(
            "active_claude_github_mcp.classification.anthropic.Anthropic",
            return_value=_mock_haiku(bad_response),
        ):
            with pytest.raises(ClassificationError, match="failed validation"):
                classify_turn(API_KEY, "some message")

    def test_strips_markdown_fences(self):
        fenced = f"```json\n{VALID_CLASSIFY_RESPONSE}\n```"
        with patch(
            "active_claude_github_mcp.classification.anthropic.Anthropic",
            return_value=_mock_haiku(fenced),
        ):
            result = classify_turn(API_KEY, "How should we handle auth?")
        assert result.destination == "discussion"

    def test_api_error_raises(self):
        import anthropic as anthropic_lib

        mock_client = MagicMock()
        mock_client.messages.create.side_effect = anthropic_lib.APIError(
            message="rate limit", request=MagicMock(), body=None
        )
        with patch(
            "active_claude_github_mcp.classification.anthropic.Anthropic",
            return_value=mock_client,
        ):
            with pytest.raises(ClassificationError, match="Anthropic API error"):
                classify_turn(API_KEY, "some message")

    def test_empty_response_raises(self):
        mock_client = MagicMock()
        mock_message = MagicMock()
        mock_message.content = []
        mock_client.messages.create.return_value = mock_message
        with patch(
            "active_claude_github_mcp.classification.anthropic.Anthropic",
            return_value=mock_client,
        ):
            with pytest.raises(ClassificationError, match="empty response"):
                classify_turn(API_KEY, "some message")


class TestDetectThemeChange:
    def test_theme_changed(self):
        comments = [
            {"id": "DC_1", "body": "Let's talk about tokens.", "createdAt": "2026-01-01"},
            {"id": "DC_2", "body": "Token expiry is key.", "createdAt": "2026-01-01"},
            {"id": "DC_abc123", "body": "Actually, the DB schema is wrong.", "createdAt": "2026-01-02"},
        ]
        with patch(
            "active_claude_github_mcp.classification.anthropic.Anthropic",
            return_value=_mock_haiku(VALID_THEME_RESPONSE),
        ):
            result = detect_theme_change(API_KEY, comments, "What about indexes?")
        assert result.theme_changed is True
        assert result.fork_point_comment_id == "DC_abc123"

    def test_no_theme_change(self):
        no_change = json.dumps({
            "theme_changed": False,
            "confidence": "high",
            "fork_point_comment_id": None,
            "original_theme": "Auth tokens",
            "new_theme": "Auth tokens",
            "suggested_title": "",
        })
        with patch(
            "active_claude_github_mcp.classification.anthropic.Anthropic",
            return_value=_mock_haiku(no_change),
        ):
            result = detect_theme_change(API_KEY, [], "What about refresh intervals?")
        assert result.theme_changed is False

    def test_empty_new_turn_raises(self):
        with pytest.raises(ValueError, match="new_turn_text"):
            detect_theme_change(API_KEY, [], "")
if __name__ == "__main__":
    import sys
    import pytest
    sys.exit(pytest.main([__file__, "-v"]))
