"""
Integration Tests für Tools Routes.

Testet die API-Endpoints /llm/tools/search und /llm/tools/health.
"""

import pytest
from unittest.mock import AsyncMock, patch, MagicMock
from fastapi.testclient import TestClient
from fastapi import FastAPI

from llm_gateway.routes.tools import router
from llm_gateway.middleware.auth import verify_api_key
from llm_gateway.services.tool_gateway import (
    ToolGateway,
    SearchResponse,
    SearchResult,
    TavilyError,
    ToolGatewayError,
    get_tool_gateway,
)


# Test App erstellen mit Auth-Override
app = FastAPI()
app.include_router(router, prefix="/tools")


# Mock für Auth-Dependency
def mock_verify_api_key():
    return "test-user"


class TestSearchEndpoint:
    """Tests für POST /tools/search."""

    def setup_method(self):
        """Setup für jeden Test."""
        # Auth-Dependency überschreiben für Tests
        app.dependency_overrides[verify_api_key] = mock_verify_api_key
        self.client = TestClient(app)

    def teardown_method(self):
        """Cleanup nach jedem Test."""
        app.dependency_overrides.clear()

    def test_search_requires_auth(self):
        """Test dass Auth erforderlich ist."""
        # Auth-Override entfernen für diesen Test
        app.dependency_overrides.clear()
        client = TestClient(app)
        response = client.post(
            "/tools/search",
            json={"query": "test"},
        )
        # Ohne API-Key sollte 401/403 kommen
        assert response.status_code in [401, 403]

    def test_search_invalid_query_too_short(self):
        """Test Validierung: Query zu kurz."""
        response = self.client.post(
            "/tools/search",
            json={"query": ""},
        )
        assert response.status_code == 422  # Validation Error

    def test_search_invalid_max_results(self):
        """Test Validierung: max_results außerhalb Grenzen."""
        response = self.client.post(
            "/tools/search",
            json={"query": "test", "max_results": 100},  # > 20
        )
        assert response.status_code == 422

    def test_search_success(self):
        """Test erfolgreiche Suche."""
        mock_gateway = MagicMock(spec=ToolGateway)
        mock_gateway.search = AsyncMock(return_value=SearchResponse(
            query="Datenschutz Schule",
            results=[
                SearchResult(
                    title="Datenschutz an Schulen",
                    url="https://example.com",
                    content="Informationen...",
                    score=0.9,
                )
            ],
            answer="Zusammenfassung",
            pii_detected=False,
            response_time_ms=1500,
        ))

        app.dependency_overrides[get_tool_gateway] = lambda: mock_gateway

        response = self.client.post(
            "/tools/search",
            json={"query": "Datenschutz Schule"},
        )

        assert response.status_code == 200
        data = response.json()
        assert data["query"] == "Datenschutz Schule"
        assert len(data["results"]) == 1
        assert data["results"][0]["title"] == "Datenschutz an Schulen"
        assert data["pii_detected"] is False

    def test_search_with_pii_redaction(self):
        """Test Suche mit PII-Erkennung."""
        mock_gateway = MagicMock(spec=ToolGateway)
        mock_gateway.search = AsyncMock(return_value=SearchResponse(
            query="Kontakt test@example.com",
            redacted_query="Kontakt [EMAIL_REDACTED]",
            results=[],
            pii_detected=True,
            pii_types=["email"],
            response_time_ms=1000,
        ))

        app.dependency_overrides[get_tool_gateway] = lambda: mock_gateway

        response = self.client.post(
            "/tools/search",
            json={"query": "Kontakt test@example.com"},
        )

        assert response.status_code == 200
        data = response.json()
        assert data["pii_detected"] is True
        assert "email" in data["pii_types"]
        assert data["redacted_query"] == "Kontakt [EMAIL_REDACTED]"

    def test_search_with_domain_filters(self):
        """Test Suche mit Domain-Filtern."""
        mock_gateway = MagicMock(spec=ToolGateway)
        mock_gateway.search = AsyncMock(return_value=SearchResponse(
            query="test",
            results=[],
            pii_detected=False,
            response_time_ms=500,
        ))

        app.dependency_overrides[get_tool_gateway] = lambda: mock_gateway

        response = self.client.post(
            "/tools/search",
            json={
                "query": "test",
                "include_domains": ["bayern.de"],
                "exclude_domains": ["wikipedia.org"],
            },
        )

        assert response.status_code == 200

        # Prüfen dass Filter an Gateway übergeben wurden
        mock_gateway.search.assert_called_once()
        call_kwargs = mock_gateway.search.call_args.kwargs
        assert call_kwargs["include_domains"] == ["bayern.de"]
        assert call_kwargs["exclude_domains"] == ["wikipedia.org"]

    def test_search_gateway_error(self):
        """Test Fehlerbehandlung bei Gateway-Fehler."""
        mock_gateway = MagicMock(spec=ToolGateway)
        mock_gateway.search = AsyncMock(side_effect=ToolGatewayError("Not configured"))

        app.dependency_overrides[get_tool_gateway] = lambda: mock_gateway

        response = self.client.post(
            "/tools/search",
            json={"query": "test"},
        )

        assert response.status_code == 503
        assert "unavailable" in response.json()["detail"].lower()

    def test_search_tavily_error(self):
        """Test Fehlerbehandlung bei Tavily-Fehler."""
        mock_gateway = MagicMock(spec=ToolGateway)
        mock_gateway.search = AsyncMock(side_effect=TavilyError("Rate limit"))

        app.dependency_overrides[get_tool_gateway] = lambda: mock_gateway

        response = self.client.post(
            "/tools/search",
            json={"query": "test"},
        )

        assert response.status_code == 502
        assert "search service error" in response.json()["detail"].lower()


class TestHealthEndpoint:
    """Tests für GET /tools/health."""

    def setup_method(self):
        """Setup für jeden Test."""
        app.dependency_overrides[verify_api_key] = mock_verify_api_key
        self.client = TestClient(app)

    def teardown_method(self):
        """Cleanup nach jedem Test."""
        app.dependency_overrides.clear()

    def test_health_requires_auth(self):
        """Test dass Auth erforderlich ist."""
        app.dependency_overrides.clear()
        client = TestClient(app)
        response = client.get("/tools/health")
        assert response.status_code in [401, 403]

    def test_health_success(self):
        """Test erfolgreicher Health Check."""
        mock_gateway = MagicMock(spec=ToolGateway)
        mock_gateway.health_check = AsyncMock(return_value={
            "tavily": {
                "configured": True,
                "healthy": True,
                "response_time_ms": 1500,
            },
            "pii_redaction": {
                "enabled": True,
            },
        })

        app.dependency_overrides[get_tool_gateway] = lambda: mock_gateway

        response = self.client.get("/tools/health")

        assert response.status_code == 200
        data = response.json()
        assert data["tavily"]["configured"] is True
        assert data["tavily"]["healthy"] is True
        assert data["pii_redaction"]["enabled"] is True

    def test_health_tavily_not_configured(self):
        """Test Health Check ohne Tavily-Konfiguration."""
        mock_gateway = MagicMock(spec=ToolGateway)
        mock_gateway.health_check = AsyncMock(return_value={
            "tavily": {
                "configured": False,
                "healthy": False,
            },
            "pii_redaction": {
                "enabled": True,
            },
        })

        app.dependency_overrides[get_tool_gateway] = lambda: mock_gateway

        response = self.client.get("/tools/health")

        assert response.status_code == 200
        data = response.json()
        assert data["tavily"]["configured"] is False


class TestSearchRequestValidation:
    """Tests für Request-Validierung."""

    def setup_method(self):
        """Setup für jeden Test."""
        app.dependency_overrides[verify_api_key] = mock_verify_api_key
        self.client = TestClient(app)

    def teardown_method(self):
        """Cleanup nach jedem Test."""
        app.dependency_overrides.clear()

    def test_query_max_length(self):
        """Test Query max length Validierung."""
        # Query mit > 1000 Zeichen
        response = self.client.post(
            "/tools/search",
            json={"query": "x" * 1001},
        )
        assert response.status_code == 422

    def test_search_depth_enum(self):
        """Test search_depth Enum Validierung."""
        mock_gateway = MagicMock(spec=ToolGateway)
        mock_gateway.search = AsyncMock(return_value=SearchResponse(
            query="test",
            results=[],
            pii_detected=False,
            response_time_ms=100,
        ))

        app.dependency_overrides[get_tool_gateway] = lambda: mock_gateway

        # Gültiger Wert
        response = self.client.post(
            "/tools/search",
            json={"query": "test", "search_depth": "advanced"},
        )
        assert response.status_code == 200

    def test_search_depth_invalid(self):
        """Test ungültiger search_depth Wert."""
        response = self.client.post(
            "/tools/search",
            json={"query": "test", "search_depth": "invalid"},
        )
        assert response.status_code == 422


class TestSearchResponseFormat:
    """Tests für Response-Format."""

    def setup_method(self):
        """Setup für jeden Test."""
        app.dependency_overrides[verify_api_key] = mock_verify_api_key
        self.client = TestClient(app)

    def teardown_method(self):
        """Cleanup nach jedem Test."""
        app.dependency_overrides.clear()

    def test_response_has_all_fields(self):
        """Test dass Response alle erforderlichen Felder hat."""
        mock_gateway = MagicMock(spec=ToolGateway)
        mock_gateway.search = AsyncMock(return_value=SearchResponse(
            query="test query",
            redacted_query=None,
            results=[
                SearchResult(
                    title="Result 1",
                    url="https://example.com/1",
                    content="Content 1",
                    score=0.95,
                    published_date="2024-01-15",
                ),
            ],
            answer="AI Summary",
            pii_detected=False,
            pii_types=[],
            response_time_ms=2000,
        ))

        app.dependency_overrides[get_tool_gateway] = lambda: mock_gateway

        response = self.client.post(
            "/tools/search",
            json={"query": "test query"},
        )

        assert response.status_code == 200
        data = response.json()

        # Pflichtfelder
        assert "query" in data
        assert "results" in data
        assert "pii_detected" in data
        assert "pii_types" in data
        assert "response_time_ms" in data

        # Optionale Felder
        assert "redacted_query" in data
        assert "answer" in data

        # Result-Felder
        result = data["results"][0]
        assert "title" in result
        assert "url" in result
        assert "content" in result
        assert "score" in result
        assert "published_date" in result
