"""Tests for LLM client abstraction layer."""

from __future__ import annotations

import os
from unittest.mock import MagicMock, patch

import pytest

from src.llm_client import AnthropicClient, OpenAIClient, create_client


class TestCreateClient:
    """Tests for the create_client factory function."""

    @patch.dict(os.environ, {"LLM_PROVIDER": "anthropic", "ANTHROPIC_API_KEY": "test-key"})
    def test_create_anthropic_client(self) -> None:
        """Default provider creates AnthropicClient."""
        client = create_client()
        assert isinstance(client, AnthropicClient)

    @patch.dict(os.environ, {"LLM_PROVIDER": "openai", "OPENAI_API_KEY": "test-key"})
    def test_create_openai_client(self) -> None:
        """Provider 'openai' creates OpenAIClient."""
        client = create_client()
        assert isinstance(client, OpenAIClient)

    @patch.dict(os.environ, {"LLM_PROVIDER": "invalid"}, clear=False)
    def test_invalid_provider_raises(self) -> None:
        """Unknown provider raises ValueError."""
        with pytest.raises(ValueError, match="Unknown LLM provider"):
            create_client()

    @patch.dict(os.environ, {}, clear=True)
    def test_default_provider_is_anthropic(self) -> None:
        """No LLM_PROVIDER env var defaults to anthropic."""
        with patch("src.llm_client.anthropic") as mock_anthropic:
            mock_anthropic.Anthropic.return_value = MagicMock()
            client = create_client()
            assert isinstance(client, AnthropicClient)


class TestAnthropicClient:
    """Tests for AnthropicClient.chat method."""

    def test_chat_calls_api_correctly(self) -> None:
        """AnthropicClient.chat sends system and messages to API."""
        mock_sdk = MagicMock()
        mock_response = MagicMock()
        mock_response.content = [MagicMock(text="Hello from Claude")]
        mock_sdk.messages.create.return_value = mock_response

        client = AnthropicClient(client=mock_sdk, model="claude-sonnet-4-20250514")
        result = client.chat(
            system="You are helpful.",
            messages=[{"role": "user", "content": "Hi"}],
        )

        assert result == "Hello from Claude"
        mock_sdk.messages.create.assert_called_once_with(
            model="claude-sonnet-4-20250514",
            max_tokens=4096,
            system="You are helpful.",
            messages=[{"role": "user", "content": "Hi"}],
        )


class TestOpenAIClient:
    """Tests for OpenAIClient.chat method."""

    def test_chat_calls_api_correctly(self) -> None:
        """OpenAIClient.chat sends system and messages to API."""
        mock_sdk = MagicMock()
        mock_choice = MagicMock()
        mock_choice.message.content = "Hello from GPT"
        mock_sdk.chat.completions.create.return_value = MagicMock(choices=[mock_choice])

        client = OpenAIClient(client=mock_sdk, model="gpt-4o")
        result = client.chat(
            system="You are helpful.",
            messages=[{"role": "user", "content": "Hi"}],
        )

        assert result == "Hello from GPT"
        mock_sdk.chat.completions.create.assert_called_once_with(
            model="gpt-4o",
            messages=[
                {"role": "system", "content": "You are helpful."},
                {"role": "user", "content": "Hi"},
            ],
        )
