"""Tests for the Anthropic integration."""

from unittest.mock import MagicMock, patch

from agentcost import AgentCost
from agentcost.integrations.anthropic import track_anthropic


def _make_ac():
    """Create a debug-mode AgentCost instance."""
    return AgentCost(debug=True)


def _make_mock_response(model="claude-sonnet-4-5-20250929", input_tokens=100, output_tokens=50):
    """Create a mock Anthropic response with usage info."""
    usage = MagicMock()
    usage.input_tokens = input_tokens
    usage.output_tokens = output_tokens

    response = MagicMock()
    response.model = model
    response.usage = usage
    return response


def _make_mock_client(response=None):
    """Create a mock Anthropic client."""
    if response is None:
        response = _make_mock_response()

    client = MagicMock()
    client.messages.create.return_value = response
    return client


class TestTrackAnthropic:
    def test_returns_wrapped_client(self):
        ac = _make_ac()
        client = _make_mock_client()
        tracked = track_anthropic(client, ac)
        assert tracked is not client
        assert hasattr(tracked, "messages")

    def test_preserves_other_attributes(self):
        ac = _make_ac()
        client = _make_mock_client()
        client.api_key = "sk-ant-test"
        tracked = track_anthropic(client, ac)
        assert tracked.api_key == "sk-ant-test"

    def test_default_agent_id(self):
        ac = _make_ac()
        client = _make_mock_client()
        tracked = track_anthropic(client, ac)
        assert tracked.messages._agent_id == "anthropic-agent"

    def test_custom_agent_id(self):
        ac = _make_ac()
        client = _make_mock_client()
        tracked = track_anthropic(client, ac, agent_id="my-claude-bot")
        assert tracked.messages._agent_id == "my-claude-bot"


class TestTrackedMessages:
    def test_create_calls_original(self):
        ac = _make_ac()
        response = _make_mock_response()
        client = _make_mock_client(response)
        tracked = track_anthropic(client, ac)

        result = tracked.messages.create(
            model="claude-sonnet-4-5-20250929",
            max_tokens=1024,
            messages=[{"role": "user", "content": "Hello"}],
        )

        client.messages.create.assert_called_once_with(
            model="claude-sonnet-4-5-20250929",
            max_tokens=1024,
            messages=[{"role": "user", "content": "Hello"}],
        )
        assert result is response

    def test_extracts_token_usage(self, capsys):
        ac = _make_ac()
        response = _make_mock_response(
            model="claude-sonnet-4-5-20250929", input_tokens=200, output_tokens=100
        )
        client = _make_mock_client(response)
        tracked = track_anthropic(client, ac)

        tracked.messages.create(
            model="claude-sonnet-4-5-20250929", max_tokens=1024, messages=[]
        )

        captured = capsys.readouterr()
        assert "claude-sonnet-4-5-20250929" in captured.err
        assert "200" in captured.err
        assert "100" in captured.err

    def test_uses_anthropic_field_names(self):
        """Anthropic uses input_tokens/output_tokens, not prompt_tokens/completion_tokens."""
        ac = _make_ac()
        response = _make_mock_response(input_tokens=300, output_tokens=150)
        client = _make_mock_client(response)
        tracked = track_anthropic(client, ac)

        with patch.object(ac._client, "enqueue") as mock_enqueue:
            tracked.messages.create(
                model="claude-sonnet-4-5-20250929", max_tokens=1024, messages=[]
            )

            event = mock_enqueue.call_args[0][0]
            assert event.tokens_in == 300
            assert event.tokens_out == 150

    def test_calculates_cost(self):
        ac = _make_ac()
        response = _make_mock_response(
            model="claude-sonnet-4-5-20250929", input_tokens=1000, output_tokens=500
        )
        client = _make_mock_client(response)
        tracked = track_anthropic(client, ac)

        with patch.object(ac._client, "enqueue") as mock_enqueue:
            tracked.messages.create(
                model="claude-sonnet-4-5-20250929", max_tokens=1024, messages=[]
            )

            event = mock_enqueue.call_args[0][0]
            assert event.cost_usd > 0
            assert event.event_type == "llm_call"
            assert event.component_name == "claude-sonnet-4-5-20250929"

    def test_handles_missing_usage(self):
        ac = _make_ac()
        response = MagicMock()
        response.model = "claude-sonnet-4-5-20250929"
        response.usage = None
        client = _make_mock_client(response)
        tracked = track_anthropic(client, ac)

        with patch.object(ac._client, "enqueue") as mock_enqueue:
            tracked.messages.create(
                model="claude-sonnet-4-5-20250929", max_tokens=1024, messages=[]
            )

            event = mock_enqueue.call_args[0][0]
            assert event.tokens_in == 0
            assert event.tokens_out == 0

    def test_enqueues_event(self):
        ac = _make_ac()
        client = _make_mock_client()
        tracked = track_anthropic(client, ac)

        with patch.object(ac._client, "enqueue") as mock_enqueue:
            tracked.messages.create(
                model="claude-sonnet-4-5-20250929", max_tokens=1024, messages=[]
            )
            assert mock_enqueue.called

    def test_links_to_active_run(self):
        ac = _make_ac()
        client = _make_mock_client()
        tracked = track_anthropic(client, ac, agent_id="standalone")

        tracker = ac.tracker("run-agent")
        with tracker.run() as run:
            with patch.object(ac._client, "enqueue") as mock_enqueue:
                tracked.messages.create(
                    model="claude-sonnet-4-5-20250929", max_tokens=1024, messages=[]
                )

                event = mock_enqueue.call_args[0][0]
                assert event.agent_id == "run-agent"
                assert event.run_id == run._run_id

    def test_measures_duration(self):
        ac = _make_ac()
        client = _make_mock_client()
        tracked = track_anthropic(client, ac)

        with patch.object(ac._client, "enqueue") as mock_enqueue:
            tracked.messages.create(
                model="claude-sonnet-4-5-20250929", max_tokens=1024, messages=[]
            )

            event = mock_enqueue.call_args[0][0]
            assert event.duration_ms >= 0
