"""Tests for Anthropic auto-instrumentation."""
from __future__ import annotations

from dataclasses import dataclass
from datetime import datetime, timezone
from typing import Any
from unittest.mock import MagicMock, patch

import pytest

from fibinaci._testing.mock_client import MockFibinaci
from fibinaci.instrumentation._wrapper import ProviderConfig, _extract_span


@dataclass
class FakeUsage:
    input_tokens: int = 80
    output_tokens: int = 40


@dataclass
class FakeResponse:
    model: str = "claude-sonnet-4-20250514"
    usage: FakeUsage = None
    stop_reason: str = "end_turn"

    def __post_init__(self):
        if self.usage is None:
            self.usage = FakeUsage()


class TestAnthropicInstrumentation:
    @pytest.fixture
    def setup_anthropic(self):
        mod = MagicMock()
        messages_cls = MagicMock()
        original_create = MagicMock(return_value=FakeResponse())
        messages_cls.create = original_create
        mod.resources.messages.Messages = messages_cls
        mod.resources.messages.AsyncMessages = MagicMock()
        return mod, messages_cls, original_create

    def test_instrument_patches_create(self, setup_anthropic, mock_fibinaci: MockFibinaci):
        mod, messages_cls, original_create = setup_anthropic
        with patch.dict("sys.modules", {
            "anthropic": mod,
            "anthropic.resources": mod.resources,
            "anthropic.resources.messages": mod.resources.messages,
        }):
            from fibinaci.instrumentation.anthropic import AnthropicInstrumentor
            inst = AnthropicInstrumentor()
            inst.instrument()
            assert messages_cls.create is not original_create
            inst.uninstrument()

    def test_span_captured_on_success(self, mock_fibinaci: MockFibinaci):
        config = ProviderConfig(
            name="anthropic",
            input_tokens_field="input_tokens",
            output_tokens_field="output_tokens",
            finish_reason_getter=lambda r: getattr(r, "stop_reason", None),
        )
        response = FakeResponse()
        started = datetime(2025, 3, 29, 12, 0, 0, tzinfo=timezone.utc)
        ended = datetime(2025, 3, 29, 12, 0, 1, tzinfo=timezone.utc)

        span_dict = _extract_span(config, {"model": "claude-sonnet-4-20250514"}, response, started, ended)

        assert span_dict["span_kind"] == "model_call"
        assert span_dict["provider"] == "anthropic"
        assert span_dict["tokens_input"] == 80
        assert span_dict["tokens_output"] == 40
        assert span_dict["status"] == "ok"
        assert span_dict["model_call"]["model_name"] == "claude-sonnet-4-20250514"
        assert span_dict["model_call"]["finish_reason"] == "end_turn"
        assert span_dict["duration_ms"] == 1000.0
