"""
Tests für die DSR (Data Subject Request) API

Testet die Proxy-Endpoints für Betroffenenanfragen.
"""

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


class TestDSRUserAPI:
    """Tests für User-Endpoints der DSR API."""

    def test_create_dsr_request_body(self):
        """Test: CreateDSRRequest Model Validierung."""
        from dsr_api import CreateDSRRequest

        # Valide Anfrage
        req = CreateDSRRequest(
            request_type="access",
            requester_email="test@example.com",
            requester_name="Max Mustermann"
        )
        assert req.request_type == "access"
        assert req.requester_email == "test@example.com"

        # Minimal-Anfrage
        req_minimal = CreateDSRRequest(
            request_type="erasure"
        )
        assert req_minimal.request_type == "erasure"
        assert req_minimal.requester_email is None

    def test_valid_request_types(self):
        """Test: Alle DSGVO-Anfragetypen."""
        valid_types = ["access", "rectification", "erasure", "restriction", "portability"]

        for req_type in valid_types:
            from dsr_api import CreateDSRRequest
            req = CreateDSRRequest(request_type=req_type)
            assert req.request_type == req_type

    @pytest.mark.asyncio
    async def test_proxy_request_success(self):
        """Test: Erfolgreiche Proxy-Anfrage."""
        from dsr_api import proxy_request

        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.content = b'{"success": true}'
        mock_response.json.return_value = {"success": True}

        with patch("httpx.AsyncClient") as mock_client:
            mock_instance = AsyncMock()
            mock_instance.get = AsyncMock(return_value=mock_response)
            mock_client.return_value.__aenter__.return_value = mock_instance

            result = await proxy_request("GET", "/dsr", "test-token")
            assert result == {"success": True}

    @pytest.mark.asyncio
    async def test_proxy_request_error(self):
        """Test: Fehler bei Proxy-Anfrage."""
        from dsr_api import proxy_request
        from fastapi import HTTPException

        mock_response = MagicMock()
        mock_response.status_code = 404
        mock_response.content = b'{"error": "Not found"}'
        mock_response.json.return_value = {"error": "Not found"}

        with patch("httpx.AsyncClient") as mock_client:
            mock_instance = AsyncMock()
            mock_instance.get = AsyncMock(return_value=mock_response)
            mock_client.return_value.__aenter__.return_value = mock_instance

            with pytest.raises(HTTPException) as exc_info:
                await proxy_request("GET", "/dsr/invalid-id", "test-token")

            assert exc_info.value.status_code == 404

    @pytest.mark.asyncio
    async def test_proxy_request_service_unavailable(self):
        """Test: Consent Service nicht erreichbar."""
        from dsr_api import proxy_request
        from fastapi import HTTPException

        with patch("httpx.AsyncClient") as mock_client:
            mock_instance = AsyncMock()
            mock_instance.get = AsyncMock(side_effect=httpx.RequestError("Connection failed"))
            mock_client.return_value.__aenter__.return_value = mock_instance

            with pytest.raises(HTTPException) as exc_info:
                await proxy_request("GET", "/dsr", "test-token")

            assert exc_info.value.status_code == 503

    def test_get_token_valid(self):
        """Test: Token-Extraktion aus Header."""
        from dsr_api import get_token

        token = get_token("Bearer valid-jwt-token")
        assert token == "valid-jwt-token"

    def test_get_token_invalid(self):
        """Test: Ungültiger Authorization Header."""
        from dsr_api import get_token
        from fastapi import HTTPException

        with pytest.raises(HTTPException) as exc_info:
            get_token(None)
        assert exc_info.value.status_code == 401

        with pytest.raises(HTTPException) as exc_info:
            get_token("InvalidHeader")
        assert exc_info.value.status_code == 401


class TestDSRAdminAPI:
    """Tests für Admin-Endpoints der DSR API."""

    def test_create_dsr_admin_request_body(self):
        """Test: Admin CreateDSRRequest Model."""
        from dsr_admin_api import CreateDSRRequest

        req = CreateDSRRequest(
            request_type="erasure",
            requester_email="user@example.com",
            requester_name="Test User",
            priority="high",
            source="admin_panel"
        )

        assert req.request_type == "erasure"
        assert req.requester_email == "user@example.com"
        assert req.priority == "high"
        assert req.source == "admin_panel"

    def test_update_dsr_request_body(self):
        """Test: UpdateDSRRequest Model."""
        from dsr_admin_api import UpdateDSRRequest

        req = UpdateDSRRequest(
            status="processing",
            priority="expedited",
            processing_notes="Daten werden zusammengestellt"
        )

        assert req.status == "processing"
        assert req.priority == "expedited"
        assert req.processing_notes == "Daten werden zusammengestellt"

    def test_verify_identity_request_body(self):
        """Test: VerifyIdentityRequest Model."""
        from dsr_admin_api import VerifyIdentityRequest

        req = VerifyIdentityRequest(method="id_card")
        assert req.method == "id_card"

        req2 = VerifyIdentityRequest(method="video_call")
        assert req2.method == "video_call"

    def test_extend_deadline_request_body(self):
        """Test: ExtendDeadlineRequest Model."""
        from dsr_admin_api import ExtendDeadlineRequest

        req = ExtendDeadlineRequest(
            reason="Komplexität der Anfrage",
            days=60
        )

        assert req.reason == "Komplexität der Anfrage"
        assert req.days == 60

    def test_complete_dsr_request_body(self):
        """Test: CompleteDSRRequest Model."""
        from dsr_admin_api import CompleteDSRRequest

        req = CompleteDSRRequest(
            summary="Alle Daten wurden bereitgestellt.",
            result_data={"files": ["export.json"]}
        )

        assert req.summary == "Alle Daten wurden bereitgestellt."
        assert "files" in req.result_data

    def test_reject_dsr_request_body(self):
        """Test: RejectDSRRequest Model."""
        from dsr_admin_api import RejectDSRRequest

        req = RejectDSRRequest(
            reason="Daten werden für Rechtsstreitigkeiten benötigt",
            legal_basis="Art. 17(3)e"
        )

        assert req.reason == "Daten werden für Rechtsstreitigkeiten benötigt"
        assert req.legal_basis == "Art. 17(3)e"

    def test_send_communication_request_body(self):
        """Test: SendCommunicationRequest Model."""
        from dsr_admin_api import SendCommunicationRequest

        req = SendCommunicationRequest(
            communication_type="dsr_processing_started",
            template_version_id="uuid-123",
            variables={"custom_field": "value"}
        )

        assert req.communication_type == "dsr_processing_started"
        assert req.template_version_id == "uuid-123"

    def test_update_exception_check_request_body(self):
        """Test: UpdateExceptionCheckRequest Model."""
        from dsr_admin_api import UpdateExceptionCheckRequest

        req = UpdateExceptionCheckRequest(
            applies=True,
            notes="Laufende Rechtsstreitigkeiten"
        )

        assert req.applies is True
        assert req.notes == "Laufende Rechtsstreitigkeiten"

    def test_create_template_version_request_body(self):
        """Test: CreateTemplateVersionRequest Model."""
        from dsr_admin_api import CreateTemplateVersionRequest

        req = CreateTemplateVersionRequest(
            version="1.1.0",
            language="de",
            subject="Eingangsbestätigung",
            body_html="<p>Inhalt</p>",
            body_text="Inhalt"
        )

        assert req.version == "1.1.0"
        assert req.language == "de"
        assert req.subject == "Eingangsbestätigung"

    def test_get_admin_token_from_header(self):
        """Test: Admin-Token aus Header extrahieren."""
        from dsr_admin_api import get_admin_token

        # Mit Bearer Token
        token = get_admin_token("Bearer admin-jwt-token")
        assert token == "admin-jwt-token"

    def test_get_admin_token_fallback(self):
        """Test: Admin-Token Fallback für Entwicklung."""
        from dsr_admin_api import get_admin_token

        # Ohne Header - generiert Dev-Token
        token = get_admin_token(None)
        assert token is not None
        assert len(token) > 0


class TestDSRRequestTypes:
    """Tests für DSR-Anfragetypen und DSGVO-Artikel."""

    def test_access_request_art_15(self):
        """Test: Auskunftsrecht (Art. 15 DSGVO)."""
        # 30 Tage Frist
        expected_deadline_days = 30
        assert expected_deadline_days == 30

    def test_rectification_request_art_16(self):
        """Test: Berichtigungsrecht (Art. 16 DSGVO)."""
        # 14 Tage empfohlen
        expected_deadline_days = 14
        assert expected_deadline_days == 14

    def test_erasure_request_art_17(self):
        """Test: Löschungsrecht (Art. 17 DSGVO)."""
        # 14 Tage empfohlen
        expected_deadline_days = 14
        assert expected_deadline_days == 14

    def test_restriction_request_art_18(self):
        """Test: Einschränkungsrecht (Art. 18 DSGVO)."""
        # 14 Tage empfohlen
        expected_deadline_days = 14
        assert expected_deadline_days == 14

    def test_portability_request_art_20(self):
        """Test: Datenübertragbarkeit (Art. 20 DSGVO)."""
        # 30 Tage Frist
        expected_deadline_days = 30
        assert expected_deadline_days == 30


class TestDSRStatusWorkflow:
    """Tests für den DSR Status-Workflow."""

    def test_valid_status_values(self):
        """Test: Alle gültigen Status-Werte."""
        valid_statuses = [
            "intake",
            "identity_verification",
            "processing",
            "completed",
            "rejected",
            "cancelled"
        ]

        for status in valid_statuses:
            assert status in valid_statuses

    def test_status_transition_intake(self):
        """Test: Erlaubte Übergänge von 'intake'."""
        allowed_from_intake = [
            "identity_verification",
            "processing",
            "rejected",
            "cancelled"
        ]

        # Completed ist NICHT direkt von intake erlaubt
        assert "completed" not in allowed_from_intake

    def test_status_transition_processing(self):
        """Test: Erlaubte Übergänge von 'processing'."""
        allowed_from_processing = [
            "completed",
            "rejected",
            "cancelled"
        ]

        # Zurück zu intake ist NICHT erlaubt
        assert "intake" not in allowed_from_processing

    def test_terminal_states(self):
        """Test: Endstatus ohne weitere Übergänge."""
        terminal_states = ["completed", "rejected", "cancelled"]

        for state in terminal_states:
            # Von Endstatus keine Übergänge möglich
            assert state in terminal_states


class TestDSRExceptionChecks:
    """Tests für Art. 17(3) Ausnahmeprüfungen."""

    def test_exception_types_art_17_3(self):
        """Test: Alle Ausnahmen nach Art. 17(3) DSGVO."""
        exceptions = {
            "art_17_3_a": "Meinungs- und Informationsfreiheit",
            "art_17_3_b": "Rechtliche Verpflichtung",
            "art_17_3_c": "Öffentliches Interesse im Gesundheitsbereich",
            "art_17_3_d": "Archivzwecke, wissenschaftliche/historische Forschung",
            "art_17_3_e": "Geltendmachung von Rechtsansprüchen"
        }

        assert len(exceptions) == 5

        for code, description in exceptions.items():
            assert code.startswith("art_17_3_")
            assert len(description) > 0

    def test_rejection_legal_bases(self):
        """Test: Rechtsgrundlagen für Ablehnung."""
        legal_bases = [
            "Art. 17(3)a",
            "Art. 17(3)b",
            "Art. 17(3)c",
            "Art. 17(3)d",
            "Art. 17(3)e",
            "Art. 12(5)"  # Offensichtlich unbegründet/exzessiv
        ]

        assert len(legal_bases) == 6
        assert "Art. 12(5)" in legal_bases


class TestDSRTemplates:
    """Tests für DSR-Vorlagen."""

    def test_template_types(self):
        """Test: Alle erwarteten Vorlagen-Typen."""
        expected_templates = [
            "dsr_receipt_access",
            "dsr_receipt_rectification",
            "dsr_receipt_erasure",
            "dsr_receipt_restriction",
            "dsr_receipt_portability",
            "dsr_identity_request",
            "dsr_processing_started",
            "dsr_processing_update",
            "dsr_clarification_request",
            "dsr_completed_access",
            "dsr_completed_rectification",
            "dsr_completed_erasure",
            "dsr_completed_restriction",
            "dsr_completed_portability",
            "dsr_restriction_lifted",
            "dsr_rejected_identity",
            "dsr_rejected_exception",
            "dsr_rejected_unfounded",
            "dsr_deadline_warning"
        ]

        assert len(expected_templates) == 19

    def test_template_variables(self):
        """Test: Standard Template-Variablen."""
        variables = [
            "{{requester_name}}",
            "{{requester_email}}",
            "{{request_number}}",
            "{{request_type_de}}",
            "{{request_date}}",
            "{{deadline_date}}",
            "{{company_name}}",
            "{{dpo_name}}",
            "{{dpo_email}}",
            "{{portal_url}}"
        ]

        for var in variables:
            assert var.startswith("{{")
            assert var.endswith("}}")
