"""E2E tests with real API providers.

These tests require real API keys set as environment variables:
- OPENAI_API_KEY
- GEMINI_API_KEY
- ANTHROPIC_API_KEY

Run with: uv run pytest tests/e2e -m e2e -v
"""

from __future__ import annotations

import os

import pytest

from llm_rotator import (
    AnthropicClient,
    GeminiClient,
    LLMRotator,
    OpenAIClient,
    RotatorConfig,
)

pytestmark = pytest.mark.e2e


def _has_openai_key() -> bool:
    return bool(os.environ.get("OPENAI_API_KEY"))


def _has_gemini_key() -> bool:
    return bool(os.environ.get("GEMINI_API_KEY"))


def _has_anthropic_key() -> bool:
    return bool(os.environ.get("ANTHROPIC_API_KEY"))


@pytest.mark.skipif(not _has_openai_key(), reason="OPENAI_API_KEY not set")
class TestLiveOpenAI:
    async def test_live_openai_simple(self):
        config = RotatorConfig(
            providers=[
                {
                    "name": "openai",
                    "client_type": "openai",
                    "priority": 1,
                    "models": ["gpt-4o-mini"],
                    "keys": [
                        {
                            "token": os.environ["OPENAI_API_KEY"],
                            "alias": "live_key",
                        }
                    ],
                }
            ]
        )
        rotator = LLMRotator(config, clients={"openai": OpenAIClient()})
        result = await rotator.complete(
            messages=[{"role": "user", "content": "Say hello in one word."}]
        )
        assert result.content
        assert result.usage.total_tokens > 0

    async def test_live_invalid_key_fallback(self):
        config = RotatorConfig(
            providers=[
                {
                    "name": "openai",
                    "client_type": "openai",
                    "priority": 1,
                    "models": ["gpt-4o-mini"],
                    "keys": [
                        {"token": "sk-invalid-key-12345", "alias": "bad_key"},
                        {
                            "token": os.environ["OPENAI_API_KEY"],
                            "alias": "good_key",
                        },
                    ],
                }
            ]
        )
        rotator = LLMRotator(config, clients={"openai": OpenAIClient()})
        result = await rotator.complete(
            messages=[{"role": "user", "content": "Say hi."}]
        )
        # Should fallback from bad key to good key
        assert result.content


@pytest.mark.skipif(not _has_gemini_key(), reason="GEMINI_API_KEY not set")
class TestLiveGemini:
    async def test_live_gemini_simple(self):
        config = RotatorConfig(
            providers=[
                {
                    "name": "gemini",
                    "client_type": "gemini",
                    "priority": 1,
                    "models": ["gemini-2.0-flash"],
                    "keys": [
                        {
                            "token": os.environ["GEMINI_API_KEY"],
                            "alias": "live_key",
                        }
                    ],
                }
            ]
        )
        rotator = LLMRotator(config, clients={"gemini": GeminiClient()})
        result = await rotator.complete(
            messages=[{"role": "user", "content": "Say hello in one word."}]
        )
        assert result.content
        assert result.usage.total_tokens > 0


@pytest.mark.skipif(not _has_anthropic_key(), reason="ANTHROPIC_API_KEY not set")
class TestLiveAnthropic:
    async def test_live_anthropic_simple(self):
        config = RotatorConfig(
            providers=[
                {
                    "name": "anthropic",
                    "client_type": "anthropic",
                    "priority": 1,
                    "models": ["claude-haiku-4-5-20251001"],
                    "keys": [
                        {
                            "token": os.environ["ANTHROPIC_API_KEY"],
                            "alias": "live_key",
                        }
                    ],
                }
            ]
        )
        rotator = LLMRotator(config, clients={"anthropic": AnthropicClient()})
        result = await rotator.complete(
            messages=[{"role": "user", "content": "Say hello in one word."}]
        )
        assert result.content
        assert result.usage.total_tokens > 0


@pytest.mark.skipif(not _has_openai_key(), reason="OPENAI_API_KEY not set")
class TestLiveToolCallingOpenAI:
    async def test_live_tool_calling_openai(self):
        config = RotatorConfig(
            providers=[
                {
                    "name": "openai",
                    "client_type": "openai",
                    "priority": 1,
                    "models": ["gpt-4o-mini"],
                    "keys": [
                        {
                            "token": os.environ["OPENAI_API_KEY"],
                            "alias": "live_key",
                        }
                    ],
                }
            ]
        )
        tools = [
            {
                "type": "function",
                "function": {
                    "name": "get_weather",
                    "description": "Get the current weather for a city",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "city": {"type": "string", "description": "City name"},
                        },
                        "required": ["city"],
                    },
                },
            }
        ]
        rotator = LLMRotator(config, clients={"openai": OpenAIClient()})
        result = await rotator.complete(
            messages=[{"role": "user", "content": "What's the weather in Paris?"}],
            tools=tools,
            tool_choice={"type": "function", "function": {"name": "get_weather"}},
        )
        assert result.tool_calls is not None
        assert len(result.tool_calls) >= 1
        assert result.tool_calls[0].name == "get_weather"


@pytest.mark.skipif(not _has_anthropic_key(), reason="ANTHROPIC_API_KEY not set")
class TestLiveToolCallingAnthropic:
    async def test_live_tool_calling_anthropic(self):
        config = RotatorConfig(
            providers=[
                {
                    "name": "anthropic",
                    "client_type": "anthropic",
                    "priority": 1,
                    "models": ["claude-haiku-4-5-20251001"],
                    "keys": [
                        {
                            "token": os.environ["ANTHROPIC_API_KEY"],
                            "alias": "live_key",
                        }
                    ],
                }
            ]
        )
        tools = [
            {
                "type": "function",
                "function": {
                    "name": "get_weather",
                    "description": "Get the current weather for a city",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "city": {"type": "string", "description": "City name"},
                        },
                        "required": ["city"],
                    },
                },
            }
        ]
        rotator = LLMRotator(config, clients={"anthropic": AnthropicClient()})
        result = await rotator.complete(
            messages=[{"role": "user", "content": "What's the weather in Paris?"}],
            tools=tools,
            tool_choice={"type": "tool", "name": "get_weather"},
        )
        assert result.tool_calls is not None
        assert len(result.tool_calls) >= 1
        assert result.tool_calls[0].name == "get_weather"
