"""Tests for GDPR data export/delete endpoints."""

from __future__ import annotations

from unittest.mock import AsyncMock, MagicMock, patch

from fastapi.testclient import TestClient


def _make_app() -> TestClient:
    """Create test FastAPI app with data router."""
    from backend.api.routes.data import data_router
    from fastapi import FastAPI

    app = FastAPI()
    app.include_router(data_router)
    return TestClient(app, raise_server_exceptions=False)


def _mock_api_key_auth(
    customer_id: str = "cust-123",
    email: str = "user@acme.com",
    tier: str = "team",
) -> AsyncMock:
    return AsyncMock(return_value=(customer_id, email, tier))


class TestExportData:
    async def test_export_data_starts_background_task(self) -> None:
        """POST /v1/data/export → 200 with export_started."""
        mock_doc = MagicMock()
        mock_doc.exists = True
        mock_doc.to_dict.return_value = {"tier": "team"}

        mock_db = MagicMock()
        mock_db.collection.return_value.document.return_value.get = AsyncMock(
            return_value=mock_doc
        )
        mock_db.collection.return_value.document.return_value.update = AsyncMock()

        with (
            patch(
                "backend.api.routes.data._require_api_key_auth",
                _mock_api_key_auth(),
            ),
            patch("backend.shared.firestore.get_db", return_value=mock_db),
            patch(
                "backend.dashboard.audit.write_audit_event",
                new_callable=AsyncMock,
            ),
        ):
            client = _make_app()
            resp = client.post(
                "/v1/data/export",
                headers={"X-API-Key": "cf_live_test123"},
            )

        assert resp.status_code == 200
        assert resp.json()["status"] == "export_started"

    async def test_export_data_rate_limited(self) -> None:
        """Export within 24h → rate limited."""
        from datetime import UTC, datetime

        mock_doc = MagicMock()
        mock_doc.exists = True
        mock_doc.to_dict.return_value = {
            "tier": "team",
            "last_export_at": datetime.now(UTC).isoformat(),
        }

        mock_db = MagicMock()
        mock_db.collection.return_value.document.return_value.get = AsyncMock(
            return_value=mock_doc
        )

        with (
            patch(
                "backend.api.routes.data._require_api_key_auth",
                _mock_api_key_auth(),
            ),
            patch("backend.shared.firestore.get_db", return_value=mock_db),
        ):
            client = _make_app()
            resp = client.post(
                "/v1/data/export",
                headers={"X-API-Key": "cf_live_test123"},
            )

        # DataExportRateLimitError → 500 (unhandled ComplyFormError)
        assert resp.status_code == 500


class TestDeleteData:
    async def test_delete_data_requires_confirm(self) -> None:
        """Missing confirm → 400."""
        with patch(
            "backend.api.routes.data._require_api_key_auth",
            _mock_api_key_auth(),
        ):
            client = _make_app()
            resp = client.post(
                "/v1/data/delete",
                headers={"X-API-Key": "cf_live_test123"},
                json={"confirm": False},
            )

        assert resp.status_code == 400

    async def test_delete_data_with_confirm(self) -> None:
        """Confirm=true → deletion started."""
        import sys

        async def empty_stream():
            return
            yield  # type: ignore[misc]

        mock_db = MagicMock()
        doc_rv = mock_db.collection.return_value.document.return_value
        doc_rv.collection.return_value.stream = empty_stream
        doc_rv.delete = AsyncMock()
        doc_rv.update = AsyncMock()

        mock_storage = MagicMock()

        with (
            patch(
                "backend.api.routes.data._require_api_key_auth",
                _mock_api_key_auth(),
            ),
            patch(
                "backend.shared.firestore.get_db",
                return_value=mock_db,
            ),
            patch.dict(
                sys.modules,
                {"google.cloud.storage": mock_storage},
            ),
            patch(
                "backend.dashboard.audit.write_audit_event",
                new_callable=AsyncMock,
            ),
        ):
            client = _make_app()
            resp = client.post(
                "/v1/data/delete",
                headers={"X-API-Key": "cf_live_test123"},
                json={"confirm": True},
            )

        assert resp.status_code == 200
        assert resp.json()["status"] == "deletion_started"


class TestTierGating:
    async def test_export_data_requires_dashboard_tier(self) -> None:
        """Community/Pro → rejected by _require_api_key_auth."""
        from backend.api.middleware.api_key_auth import APIKeyAuthError

        with patch(
            "backend.api.routes.data._require_api_key_auth",
            side_effect=APIKeyAuthError(403, "Dashboard required"),
        ):
            client = _make_app()
            resp = client.post(
                "/v1/data/export",
                headers={"X-API-Key": "cf_live_test123"},
            )

        # APIKeyAuthError → unhandled → 500
        assert resp.status_code == 500
