"""
Tests fuer LLM Comparison Route.
"""

import pytest
from unittest.mock import AsyncMock, patch, MagicMock
from datetime import datetime


class TestComparisonModels:
    """Tests fuer die Pydantic Models."""

    def test_comparison_request_defaults(self):
        """Test ComparisonRequest mit Default-Werten."""
        from llm_gateway.routes.comparison import ComparisonRequest

        req = ComparisonRequest(prompt="Test prompt")

        assert req.prompt == "Test prompt"
        assert req.system_prompt is None
        assert req.enable_openai is True
        assert req.enable_claude is True
        assert req.enable_selfhosted_tavily is True
        assert req.enable_selfhosted_edusearch is True
        assert req.selfhosted_model == "llama3.2:3b"
        assert req.temperature == 0.7
        assert req.top_p == 0.9
        assert req.max_tokens == 2048
        assert req.search_results_count == 5

    def test_comparison_request_custom_values(self):
        """Test ComparisonRequest mit benutzerdefinierten Werten."""
        from llm_gateway.routes.comparison import ComparisonRequest

        req = ComparisonRequest(
            prompt="Custom prompt",
            system_prompt="Du bist ein Experte",
            enable_openai=False,
            enable_claude=True,
            enable_selfhosted_tavily=False,
            enable_selfhosted_edusearch=True,
            selfhosted_model="llama3.1:8b",
            temperature=0.5,
            top_p=0.8,
            max_tokens=1024,
            search_results_count=10,
            edu_search_filters={"language": ["de"], "doc_type": ["Lehrplan"]},
        )

        assert req.prompt == "Custom prompt"
        assert req.system_prompt == "Du bist ein Experte"
        assert req.enable_openai is False
        assert req.selfhosted_model == "llama3.1:8b"
        assert req.temperature == 0.5
        assert req.edu_search_filters == {"language": ["de"], "doc_type": ["Lehrplan"]}

    def test_llm_response_model(self):
        """Test LLMResponse Model."""
        from llm_gateway.routes.comparison import LLMResponse

        response = LLMResponse(
            provider="openai",
            model="gpt-4o-mini",
            response="Test response",
            latency_ms=500,
            tokens_used=100,
        )

        assert response.provider == "openai"
        assert response.model == "gpt-4o-mini"
        assert response.response == "Test response"
        assert response.latency_ms == 500
        assert response.tokens_used == 100
        assert response.error is None
        assert response.search_results is None

    def test_llm_response_with_error(self):
        """Test LLMResponse mit Fehler."""
        from llm_gateway.routes.comparison import LLMResponse

        response = LLMResponse(
            provider="claude",
            model="claude-3-5-sonnet",
            response="",
            latency_ms=100,
            error="API Key nicht konfiguriert",
        )

        assert response.error == "API Key nicht konfiguriert"
        assert response.response == ""

    def test_llm_response_with_search_results(self):
        """Test LLMResponse mit Suchergebnissen."""
        from llm_gateway.routes.comparison import LLMResponse

        search_results = [
            {"title": "Lehrplan Mathe", "url": "https://example.com", "content": "..."},
            {"title": "Bildungsstandards", "url": "https://kmk.org", "content": "..."},
        ]

        response = LLMResponse(
            provider="selfhosted_edusearch",
            model="llama3.2:3b",
            response="Antwort mit Quellen",
            latency_ms=2000,
            search_results=search_results,
        )

        assert len(response.search_results) == 2
        assert response.search_results[0]["title"] == "Lehrplan Mathe"


class TestComparisonResponse:
    """Tests fuer ComparisonResponse."""

    def test_comparison_response_structure(self):
        """Test ComparisonResponse Struktur."""
        from llm_gateway.routes.comparison import ComparisonResponse, LLMResponse

        responses = [
            LLMResponse(
                provider="openai",
                model="gpt-4o-mini",
                response="OpenAI Antwort",
                latency_ms=400,
            ),
            LLMResponse(
                provider="claude",
                model="claude-3-5-sonnet",
                response="Claude Antwort",
                latency_ms=600,
            ),
        ]

        result = ComparisonResponse(
            comparison_id="cmp-test123",
            prompt="Was ist 1+1?",
            system_prompt="Du bist ein Mathe-Lehrer",
            responses=responses,
        )

        assert result.comparison_id == "cmp-test123"
        assert result.prompt == "Was ist 1+1?"
        assert result.system_prompt == "Du bist ein Mathe-Lehrer"
        assert len(result.responses) == 2
        assert result.responses[0].provider == "openai"
        assert result.responses[1].provider == "claude"


class TestSystemPromptStore:
    """Tests fuer System Prompt Management."""

    def test_default_system_prompts_exist(self):
        """Test dass Standard-Prompts existieren."""
        from llm_gateway.routes.comparison import _system_prompts_store

        assert "default" in _system_prompts_store
        assert "curriculum" in _system_prompts_store
        assert "worksheet" in _system_prompts_store

    def test_default_prompt_structure(self):
        """Test Struktur der Standard-Prompts."""
        from llm_gateway.routes.comparison import _system_prompts_store

        default = _system_prompts_store["default"]
        assert "id" in default
        assert "name" in default
        assert "prompt" in default
        assert "created_at" in default

        assert default["id"] == "default"
        assert "Lehrer" in default["prompt"] or "Assistent" in default["prompt"]


class TestSearchFunctions:
    """Tests fuer Such-Funktionen."""

    @pytest.mark.asyncio
    async def test_search_tavily_no_api_key(self):
        """Test Tavily Suche ohne API Key."""
        from llm_gateway.routes.comparison import _search_tavily

        with patch.dict("os.environ", {}, clear=True):
            results = await _search_tavily("test query", 5)
            assert results == []

    @pytest.mark.asyncio
    async def test_search_edusearch_connection_error(self):
        """Test EduSearch bei Verbindungsfehler."""
        from llm_gateway.routes.comparison import _search_edusearch

        with patch("httpx.AsyncClient") as mock_client:
            mock_instance = AsyncMock()
            mock_instance.__aenter__ = AsyncMock(return_value=mock_instance)
            mock_instance.__aexit__ = AsyncMock(return_value=None)
            mock_instance.post = AsyncMock(side_effect=Exception("Connection refused"))
            mock_client.return_value = mock_instance

            results = await _search_edusearch("test query", 5)
            assert results == []


class TestLLMCalls:
    """Tests fuer LLM-Aufrufe."""

    @pytest.mark.asyncio
    async def test_call_openai_no_api_key(self):
        """Test OpenAI Aufruf ohne API Key."""
        from llm_gateway.routes.comparison import _call_openai

        with patch.dict("os.environ", {}, clear=True):
            result = await _call_openai("Test prompt", None)

            assert result.provider == "openai"
            assert result.error is not None
            assert "OPENAI_API_KEY" in result.error

    @pytest.mark.asyncio
    async def test_call_claude_no_api_key(self):
        """Test Claude Aufruf ohne API Key."""
        from llm_gateway.routes.comparison import _call_claude

        with patch.dict("os.environ", {}, clear=True):
            result = await _call_claude("Test prompt", None)

            assert result.provider == "claude"
            assert result.error is not None
            assert "ANTHROPIC_API_KEY" in result.error


class TestComparisonEndpoints:
    """Integration Tests fuer die API Endpoints."""

    @pytest.fixture
    def mock_verify_api_key(self):
        """Mock fuer API Key Verifizierung."""
        with patch("llm_gateway.routes.comparison.verify_api_key") as mock:
            mock.return_value = "test-user"
            yield mock

    @pytest.mark.asyncio
    async def test_list_system_prompts(self, mock_verify_api_key):
        """Test GET /comparison/prompts."""
        from llm_gateway.routes.comparison import list_system_prompts

        result = await list_system_prompts(_="test-user")

        assert "prompts" in result
        assert len(result["prompts"]) >= 3  # default, curriculum, worksheet

    @pytest.mark.asyncio
    async def test_get_system_prompt(self, mock_verify_api_key):
        """Test GET /comparison/prompts/{prompt_id}."""
        from llm_gateway.routes.comparison import get_system_prompt

        result = await get_system_prompt("default", _="test-user")

        assert result["id"] == "default"
        assert "name" in result
        assert "prompt" in result

    @pytest.mark.asyncio
    async def test_get_system_prompt_not_found(self, mock_verify_api_key):
        """Test GET /comparison/prompts/{prompt_id} mit unbekannter ID."""
        from fastapi import HTTPException
        from llm_gateway.routes.comparison import get_system_prompt

        with pytest.raises(HTTPException) as exc_info:
            await get_system_prompt("nonexistent-id", _="test-user")

        assert exc_info.value.status_code == 404

    @pytest.mark.asyncio
    async def test_get_comparison_history(self, mock_verify_api_key):
        """Test GET /comparison/history."""
        from llm_gateway.routes.comparison import get_comparison_history

        result = await get_comparison_history(limit=10, _="test-user")

        assert "comparisons" in result
        assert isinstance(result["comparisons"], list)


class TestProviderMapping:
    """Tests fuer Provider-Label und -Color Mapping."""

    def test_provider_labels(self):
        """Test dass alle Provider Labels haben."""
        provider_labels = {
            "openai": "OpenAI GPT-4o-mini",
            "claude": "Claude 3.5 Sonnet",
            "selfhosted_tavily": "Self-hosted + Tavily",
            "selfhosted_edusearch": "Self-hosted + EduSearch",
        }

        for key, expected in provider_labels.items():
            assert key in ["openai", "claude", "selfhosted_tavily", "selfhosted_edusearch"]


class TestParameterValidation:
    """Tests fuer Parameter-Validierung."""

    def test_temperature_range(self):
        """Test Temperature Bereich 0-2."""
        from llm_gateway.routes.comparison import ComparisonRequest
        from pydantic import ValidationError

        # Gueltige Werte
        req = ComparisonRequest(prompt="test", temperature=0.0)
        assert req.temperature == 0.0

        req = ComparisonRequest(prompt="test", temperature=2.0)
        assert req.temperature == 2.0

        # Ungueltige Werte
        with pytest.raises(ValidationError):
            ComparisonRequest(prompt="test", temperature=-0.1)

        with pytest.raises(ValidationError):
            ComparisonRequest(prompt="test", temperature=2.1)

    def test_top_p_range(self):
        """Test Top-P Bereich 0-1."""
        from llm_gateway.routes.comparison import ComparisonRequest
        from pydantic import ValidationError

        # Gueltige Werte
        req = ComparisonRequest(prompt="test", top_p=0.0)
        assert req.top_p == 0.0

        req = ComparisonRequest(prompt="test", top_p=1.0)
        assert req.top_p == 1.0

        # Ungueltige Werte
        with pytest.raises(ValidationError):
            ComparisonRequest(prompt="test", top_p=-0.1)

        with pytest.raises(ValidationError):
            ComparisonRequest(prompt="test", top_p=1.1)

    def test_max_tokens_range(self):
        """Test Max Tokens Bereich 1-8192."""
        from llm_gateway.routes.comparison import ComparisonRequest
        from pydantic import ValidationError

        # Gueltige Werte
        req = ComparisonRequest(prompt="test", max_tokens=1)
        assert req.max_tokens == 1

        req = ComparisonRequest(prompt="test", max_tokens=8192)
        assert req.max_tokens == 8192

        # Ungueltige Werte
        with pytest.raises(ValidationError):
            ComparisonRequest(prompt="test", max_tokens=0)

        with pytest.raises(ValidationError):
            ComparisonRequest(prompt="test", max_tokens=8193)

    def test_search_results_count_range(self):
        """Test Search Results Count Bereich 1-20."""
        from llm_gateway.routes.comparison import ComparisonRequest
        from pydantic import ValidationError

        # Gueltige Werte
        req = ComparisonRequest(prompt="test", search_results_count=1)
        assert req.search_results_count == 1

        req = ComparisonRequest(prompt="test", search_results_count=20)
        assert req.search_results_count == 20

        # Ungueltige Werte
        with pytest.raises(ValidationError):
            ComparisonRequest(prompt="test", search_results_count=0)

        with pytest.raises(ValidationError):
            ComparisonRequest(prompt="test", search_results_count=21)
