"""Tests for VVT routes and schemas (vvt_routes.py, vvt_models.py)."""

import pytest
from unittest.mock import MagicMock, patch
from datetime import datetime, date, timedelta, timezone
import uuid

from compliance.api.schemas import (
    VVTActivityCreate,
    VVTActivityUpdate,
    VVTOrganizationUpdate,
    VVTStatsResponse,
)
from compliance.api.vvt_routes import _activity_to_response, _log_audit
from compliance.db.vvt_models import VVTActivityDB, VVTOrganizationDB, VVTAuditLogDB


# =============================================================================
# Schema Tests
# =============================================================================

class TestVVTActivityCreate:
    def test_default_values(self):
        req = VVTActivityCreate(vvt_id="VVT-001", name="Test Verarbeitung")
        assert req.vvt_id == "VVT-001"
        assert req.name == "Test Verarbeitung"
        assert req.status == "DRAFT"
        assert req.protection_level == "MEDIUM"
        assert req.dpia_required is False
        assert req.purposes == []
        assert req.legal_bases == []

    def test_full_values(self):
        req = VVTActivityCreate(
            vvt_id="VVT-002",
            name="Gehaltsabrechnung",
            description="Verarbeitung von Gehaltsabrechnungsdaten",
            purposes=["Vertragserfuellung"],
            legal_bases=["Art. 6 Abs. 1b DSGVO"],
            data_subject_categories=["Mitarbeiter"],
            personal_data_categories=["Bankdaten", "Steuer-ID"],
            status="APPROVED",
            dpia_required=False,
        )
        assert req.vvt_id == "VVT-002"
        assert req.status == "APPROVED"
        assert len(req.purposes) == 1
        assert len(req.personal_data_categories) == 2

    def test_serialization(self):
        req = VVTActivityCreate(vvt_id="VVT-003", name="Test")
        data = req.model_dump()
        assert data["vvt_id"] == "VVT-003"
        assert isinstance(data["purposes"], list)
        assert isinstance(data["retention_period"], dict)


class TestVVTActivityUpdate:
    def test_partial_update(self):
        req = VVTActivityUpdate(status="APPROVED")
        data = req.model_dump(exclude_none=True)
        assert data == {"status": "APPROVED"}

    def test_empty_update(self):
        req = VVTActivityUpdate()
        data = req.model_dump(exclude_none=True)
        assert data == {}

    def test_multi_field_update(self):
        req = VVTActivityUpdate(
            name="Updated Name",
            dpia_required=True,
            protection_level="HIGH",
        )
        data = req.model_dump(exclude_none=True)
        assert data["name"] == "Updated Name"
        assert data["dpia_required"] is True
        assert data["protection_level"] == "HIGH"


class TestVVTOrganizationUpdate:
    def test_defaults(self):
        req = VVTOrganizationUpdate()
        data = req.model_dump(exclude_none=True)
        assert data == {}

    def test_partial_update(self):
        req = VVTOrganizationUpdate(
            organization_name="BreakPilot GmbH",
            dpo_name="Max Mustermann",
        )
        data = req.model_dump(exclude_none=True)
        assert data["organization_name"] == "BreakPilot GmbH"
        assert data["dpo_name"] == "Max Mustermann"


class TestVVTStatsResponse:
    def test_stats_response(self):
        stats = VVTStatsResponse(
            total=5,
            by_status={"DRAFT": 3, "APPROVED": 2},
            by_business_function={"HR": 2, "IT": 3},
            dpia_required_count=1,
            third_country_count=0,
            draft_count=3,
            approved_count=2,
            overdue_review_count=1,
        )
        assert stats.total == 5
        assert stats.by_status["DRAFT"] == 3
        assert stats.dpia_required_count == 1
        assert stats.overdue_review_count == 1

    def test_stats_overdue_default_zero(self):
        stats = VVTStatsResponse(
            total=0,
            by_status={},
            by_business_function={},
            dpia_required_count=0,
            third_country_count=0,
            draft_count=0,
            approved_count=0,
        )
        assert stats.overdue_review_count == 0


# =============================================================================
# DB Model Tests
# =============================================================================

class TestVVTModels:
    def test_activity_defaults(self):
        act = VVTActivityDB()
        assert act.status is None or act.status == 'DRAFT'
        assert act.dpia_required is False or act.dpia_required is None

    def test_activity_repr(self):
        act = VVTActivityDB()
        act.vvt_id = "VVT-001"
        act.name = "Test"
        assert "VVT-001" in repr(act)

    def test_organization_repr(self):
        org = VVTOrganizationDB()
        org.organization_name = "Test GmbH"
        assert "Test GmbH" in repr(org)

    def test_audit_log_repr(self):
        log = VVTAuditLogDB()
        log.action = "CREATE"
        log.entity_type = "activity"
        assert "CREATE" in repr(log)


# =============================================================================
# Helper Function Tests
# =============================================================================

class TestActivityToResponse:
    def _make_activity(self, **kwargs) -> VVTActivityDB:
        act = VVTActivityDB()
        act.id = uuid.uuid4()
        act.vvt_id = kwargs.get("vvt_id", "VVT-001")
        act.name = kwargs.get("name", "Test")
        act.description = kwargs.get("description", None)
        act.purposes = kwargs.get("purposes", [])
        act.legal_bases = kwargs.get("legal_bases", [])
        act.data_subject_categories = kwargs.get("data_subject_categories", [])
        act.personal_data_categories = kwargs.get("personal_data_categories", [])
        act.recipient_categories = kwargs.get("recipient_categories", [])
        act.third_country_transfers = kwargs.get("third_country_transfers", [])
        act.retention_period = kwargs.get("retention_period", {})
        act.tom_description = kwargs.get("tom_description", None)
        act.business_function = kwargs.get("business_function", None)
        act.systems = kwargs.get("systems", [])
        act.deployment_model = kwargs.get("deployment_model", None)
        act.data_sources = kwargs.get("data_sources", [])
        act.data_flows = kwargs.get("data_flows", [])
        act.protection_level = kwargs.get("protection_level", "MEDIUM")
        act.dpia_required = kwargs.get("dpia_required", False)
        act.structured_toms = kwargs.get("structured_toms", {})
        act.status = kwargs.get("status", "DRAFT")
        act.responsible = kwargs.get("responsible", None)
        act.owner = kwargs.get("owner", None)
        act.last_reviewed_at = kwargs.get("last_reviewed_at", None)
        act.next_review_at = kwargs.get("next_review_at", None)
        act.created_by = kwargs.get("created_by", None)
        act.dsfa_id = kwargs.get("dsfa_id", None)
        act.created_at = datetime.now(timezone.utc)
        act.updated_at = None
        return act

    def test_basic_conversion(self):
        act = self._make_activity(vvt_id="VVT-001", name="Kundendaten")
        response = _activity_to_response(act)
        assert response.vvt_id == "VVT-001"
        assert response.name == "Kundendaten"
        assert response.status == "DRAFT"
        assert response.protection_level == "MEDIUM"

    def test_null_lists_become_empty(self):
        act = self._make_activity()
        act.purposes = None
        act.legal_bases = None
        response = _activity_to_response(act)
        assert response.purposes == []
        assert response.legal_bases == []

    def test_null_dicts_become_empty(self):
        act = self._make_activity()
        act.retention_period = None
        act.structured_toms = None
        response = _activity_to_response(act)
        assert response.retention_period == {}
        assert response.structured_toms == {}


class TestLogAudit:
    def test_creates_audit_entry(self):
        mock_db = MagicMock()
        act_id = uuid.uuid4()
        _log_audit(
            db=mock_db,
            tenant_id="9282a473-5c95-4b3a-bf78-0ecc0ec71d3e",
            action="CREATE",
            entity_type="activity",
            entity_id=act_id,
            changed_by="test_user",
            new_values={"name": "Test"},
        )
        mock_db.add.assert_called_once()
        added = mock_db.add.call_args[0][0]
        assert added.action == "CREATE"
        assert added.entity_type == "activity"
        assert added.entity_id == act_id

    def test_defaults_changed_by(self):
        mock_db = MagicMock()
        _log_audit(mock_db, tenant_id="9282a473-5c95-4b3a-bf78-0ecc0ec71d3e", action="DELETE", entity_type="activity")
        added = mock_db.add.call_args[0][0]
        assert added.changed_by == "system"


# =============================================================================
# Consolidation Tests (Go → Python feature parity)
# =============================================================================

class TestVVTConsolidationSchemas:
    """Tests for new fields ported from Go: review dates, created_by, dsfa_id."""

    def test_activity_create_with_review_dates(self):
        now = datetime.now(timezone.utc)
        future = now + timedelta(days=365)
        req = VVTActivityCreate(
            vvt_id="VVT-REV-001",
            name="Review-Test",
            last_reviewed_at=now,
            next_review_at=future,
        )
        assert req.last_reviewed_at == now
        assert req.next_review_at == future

    def test_activity_create_sets_created_by(self):
        req = VVTActivityCreate(
            vvt_id="VVT-CB-001",
            name="Created-By Test",
            created_by="admin@example.com",
        )
        assert req.created_by == "admin@example.com"

    def test_activity_create_created_by_defaults_none(self):
        req = VVTActivityCreate(vvt_id="VVT-CB-002", name="Default Test")
        assert req.created_by is None

    def test_activity_create_with_dsfa_id(self):
        dsfa_uuid = str(uuid.uuid4())
        req = VVTActivityCreate(
            vvt_id="VVT-DSFA-001",
            name="DSFA-Link Test",
            dsfa_id=dsfa_uuid,
        )
        assert req.dsfa_id == dsfa_uuid

    def test_activity_update_review_dates(self):
        now = datetime.now(timezone.utc)
        req = VVTActivityUpdate(
            last_reviewed_at=now,
            next_review_at=now + timedelta(days=180),
        )
        data = req.model_dump(exclude_none=True)
        assert "last_reviewed_at" in data
        assert "next_review_at" in data

    def test_activity_update_dsfa_id(self):
        dsfa_uuid = str(uuid.uuid4())
        req = VVTActivityUpdate(dsfa_id=dsfa_uuid)
        data = req.model_dump(exclude_none=True)
        assert data["dsfa_id"] == dsfa_uuid


class TestVVTConsolidationResponse:
    """Tests for new fields in response mapping."""

    def _make_activity(self, **kwargs) -> VVTActivityDB:
        act = VVTActivityDB()
        act.id = uuid.uuid4()
        act.vvt_id = kwargs.get("vvt_id", "VVT-001")
        act.name = kwargs.get("name", "Test")
        act.description = None
        act.purposes = []
        act.legal_bases = []
        act.data_subject_categories = []
        act.personal_data_categories = []
        act.recipient_categories = []
        act.third_country_transfers = []
        act.retention_period = {}
        act.tom_description = None
        act.business_function = None
        act.systems = []
        act.deployment_model = None
        act.data_sources = []
        act.data_flows = []
        act.protection_level = "MEDIUM"
        act.dpia_required = False
        act.structured_toms = {}
        act.status = "DRAFT"
        act.responsible = None
        act.owner = None
        act.last_reviewed_at = kwargs.get("last_reviewed_at", None)
        act.next_review_at = kwargs.get("next_review_at", None)
        act.created_by = kwargs.get("created_by", None)
        act.dsfa_id = kwargs.get("dsfa_id", None)
        act.created_at = datetime.now(timezone.utc)
        act.updated_at = None
        return act

    def test_response_includes_review_dates(self):
        now = datetime.now(timezone.utc)
        future = now + timedelta(days=365)
        act = self._make_activity(last_reviewed_at=now, next_review_at=future)
        resp = _activity_to_response(act)
        assert resp.last_reviewed_at == now
        assert resp.next_review_at == future

    def test_response_includes_created_by(self):
        act = self._make_activity(created_by="admin@example.com")
        resp = _activity_to_response(act)
        assert resp.created_by == "admin@example.com"

    def test_response_includes_dsfa_id(self):
        dsfa_uuid = uuid.uuid4()
        act = self._make_activity(dsfa_id=dsfa_uuid)
        resp = _activity_to_response(act)
        assert resp.dsfa_id == str(dsfa_uuid)

    def test_response_null_new_fields(self):
        act = self._make_activity()
        resp = _activity_to_response(act)
        assert resp.last_reviewed_at is None
        assert resp.next_review_at is None
        assert resp.created_by is None
        assert resp.dsfa_id is None


class TestVVTCsvExport:
    """Tests for CSV export functionality."""

    def _collect_csv_body(self, response) -> str:
        """Extract text from StreamingResponse (async generator)."""
        import asyncio
        async def _read():
            chunks = []
            async for chunk in response.body_iterator:
                chunks.append(chunk)
            return ''.join(chunks)
        return asyncio.get_event_loop().run_until_complete(_read())

    def test_export_csv_format(self):
        from compliance.api.vvt_routes import _export_csv
        act = VVTActivityDB()
        act.id = uuid.uuid4()
        act.vvt_id = "VVT-CSV-001"
        act.name = "CSV Test"
        act.purposes = ["Zweck A", "Zweck B"]
        act.legal_bases = ["Art. 6 Abs. 1b"]
        act.personal_data_categories = ["Email"]
        act.data_subject_categories = ["Kunden"]
        act.recipient_categories = ["IT-Dienstleister"]
        act.third_country_transfers = ["USA"]
        act.retention_period = {"duration": "3 Jahre"}
        act.status = "APPROVED"
        act.responsible = "DSB"
        act.created_by = "admin"
        act.created_at = datetime(2026, 1, 15, 10, 30)
        act.updated_at = None

        response = _export_csv([act])
        text = self._collect_csv_body(response)
        assert 'VVT-CSV-001' in text
        assert 'CSV Test' in text
        assert 'APPROVED' in text

    def test_export_csv_semicolon_separator(self):
        from compliance.api.vvt_routes import _export_csv
        act = VVTActivityDB()
        act.id = uuid.uuid4()
        act.vvt_id = "VVT-SEP-001"
        act.name = "Separator Test"
        act.purposes = []
        act.legal_bases = []
        act.personal_data_categories = []
        act.data_subject_categories = []
        act.recipient_categories = []
        act.third_country_transfers = []
        act.retention_period = {}
        act.status = "DRAFT"
        act.responsible = ""
        act.created_by = "system"
        act.created_at = datetime(2026, 3, 1, 12, 0)
        act.updated_at = None

        response = _export_csv([act])
        text = self._collect_csv_body(response)
        lines = text.strip().split('\n')
        header = lines[0]
        assert ';' in header
        assert 'ID;VVT-ID;Name' in header.replace('\ufeff', '')

    def test_export_csv_empty_list(self):
        from compliance.api.vvt_routes import _export_csv
        response = _export_csv([])
        text = self._collect_csv_body(response)
        lines = text.strip().split('\n')
        assert len(lines) == 1


# =============================================================================
# API Endpoint Tests (TestClient + mock DB)
# =============================================================================

from fastapi.testclient import TestClient
from fastapi import FastAPI
from compliance.api.vvt_routes import router

_app = FastAPI()
_app.include_router(router)
_client = TestClient(_app)

DEFAULT_TENANT = "9282a473-5c95-4b3a-bf78-0ecc0ec71d3e"


def _make_db_activity(**kwargs):
    """Create a mock VVTActivityDB object for query results."""
    act = VVTActivityDB()
    act.id = kwargs.get("id", uuid.uuid4())
    act.tenant_id = kwargs.get("tenant_id", DEFAULT_TENANT)
    act.vvt_id = kwargs.get("vvt_id", "VVT-001")
    act.name = kwargs.get("name", "Test Verarbeitung")
    act.description = kwargs.get("description", None)
    act.purposes = kwargs.get("purposes", ["Vertragserfuellung"])
    act.legal_bases = kwargs.get("legal_bases", ["Art. 6 Abs. 1b"])
    act.data_subject_categories = kwargs.get("data_subject_categories", ["Kunden"])
    act.personal_data_categories = kwargs.get("personal_data_categories", ["Email"])
    act.recipient_categories = kwargs.get("recipient_categories", [])
    act.third_country_transfers = kwargs.get("third_country_transfers", [])
    act.retention_period = kwargs.get("retention_period", {"duration": "3 Jahre"})
    act.tom_description = kwargs.get("tom_description", None)
    act.business_function = kwargs.get("business_function", "IT")
    act.systems = kwargs.get("systems", [])
    act.deployment_model = kwargs.get("deployment_model", None)
    act.data_sources = kwargs.get("data_sources", [])
    act.data_flows = kwargs.get("data_flows", [])
    act.protection_level = kwargs.get("protection_level", "MEDIUM")
    act.dpia_required = kwargs.get("dpia_required", False)
    act.structured_toms = kwargs.get("structured_toms", {})
    act.status = kwargs.get("status", "DRAFT")
    act.responsible = kwargs.get("responsible", None)
    act.owner = kwargs.get("owner", None)
    act.last_reviewed_at = kwargs.get("last_reviewed_at", None)
    act.next_review_at = kwargs.get("next_review_at", None)
    act.created_by = kwargs.get("created_by", "system")
    act.dsfa_id = kwargs.get("dsfa_id", None)
    act.created_at = kwargs.get("created_at", datetime(2026, 1, 15, 10, 0))
    act.updated_at = kwargs.get("updated_at", None)
    return act


def _make_db_org(**kwargs):
    """Create a mock VVTOrganizationDB object."""
    org = VVTOrganizationDB()
    org.id = kwargs.get("id", uuid.uuid4())
    org.tenant_id = kwargs.get("tenant_id", DEFAULT_TENANT)
    org.organization_name = kwargs.get("organization_name", "BreakPilot GmbH")
    org.industry = kwargs.get("industry", "IT")
    org.locations = kwargs.get("locations", ["Berlin"])
    org.employee_count = kwargs.get("employee_count", 50)
    org.dpo_name = kwargs.get("dpo_name", "Max DSB")
    org.dpo_contact = kwargs.get("dpo_contact", "dsb@example.com")
    org.vvt_version = kwargs.get("vvt_version", "1.0")
    org.last_review_date = kwargs.get("last_review_date", None)
    org.next_review_date = kwargs.get("next_review_date", None)
    org.review_interval = kwargs.get("review_interval", "annual")
    org.created_at = kwargs.get("created_at", datetime(2026, 1, 1))
    org.updated_at = kwargs.get("updated_at", None)
    return org


def _make_audit_entry(**kwargs):
    """Create a mock VVTAuditLogDB object."""
    entry = VVTAuditLogDB()
    entry.id = kwargs.get("id", uuid.uuid4())
    entry.tenant_id = kwargs.get("tenant_id", DEFAULT_TENANT)
    entry.action = kwargs.get("action", "CREATE")
    entry.entity_type = kwargs.get("entity_type", "activity")
    entry.entity_id = kwargs.get("entity_id", uuid.uuid4())
    entry.changed_by = kwargs.get("changed_by", "system")
    entry.old_values = kwargs.get("old_values", None)
    entry.new_values = kwargs.get("new_values", {"name": "Test"})
    entry.created_at = kwargs.get("created_at", datetime(2026, 1, 15, 10, 0))
    return entry


@pytest.fixture
def mock_db():
    from classroom_engine.database import get_db
    from compliance.api.tenant_utils import get_tenant_id
    db = MagicMock()
    _app.dependency_overrides[get_db] = lambda: db
    _app.dependency_overrides[get_tenant_id] = lambda: DEFAULT_TENANT
    yield db
    _app.dependency_overrides.clear()


class TestExportEndpoint:
    """Tests for GET /vvt/export (JSON and CSV)."""

    def test_export_json_with_activities(self, mock_db):
        act = _make_db_activity(vvt_id="VVT-EXP-001", name="Export Test")
        org = _make_db_org()
        # mock chained query for org
        mock_db.query.return_value.filter.return_value.order_by.return_value.first.return_value = org
        # mock chained query for activities
        mock_db.query.return_value.filter.return_value.order_by.return_value.all.return_value = [act]

        resp = _client.get("/vvt/export?format=json")
        assert resp.status_code == 200
        data = resp.json()
        assert "exported_at" in data
        assert "organization" in data
        assert data["organization"]["name"] == "BreakPilot GmbH"
        assert len(data["activities"]) == 1
        assert data["activities"][0]["vvt_id"] == "VVT-EXP-001"

    def test_export_json_empty_dataset(self, mock_db):
        mock_db.query.return_value.filter.return_value.order_by.return_value.first.return_value = None
        mock_db.query.return_value.filter.return_value.order_by.return_value.all.return_value = []

        resp = _client.get("/vvt/export?format=json")
        assert resp.status_code == 200
        data = resp.json()
        assert data["organization"] is None
        assert data["activities"] == []

    def test_export_csv_returns_streaming_response(self, mock_db):
        act = _make_db_activity(vvt_id="VVT-CSV-E01", name="CSV Endpoint Test")
        mock_db.query.return_value.filter.return_value.order_by.return_value.first.return_value = None
        mock_db.query.return_value.filter.return_value.order_by.return_value.all.return_value = [act]

        resp = _client.get("/vvt/export?format=csv")
        assert resp.status_code == 200
        assert "text/csv" in resp.headers.get("content-type", "")
        assert "attachment" in resp.headers.get("content-disposition", "")
        body = resp.text
        assert "VVT-CSV-E01" in body
        assert "CSV Endpoint Test" in body

    def test_export_invalid_format_rejected(self, mock_db):
        resp = _client.get("/vvt/export?format=xml")
        assert resp.status_code == 422  # validation error


class TestStatsEndpoint:
    """Tests for GET /vvt/stats."""

    def test_stats_empty_tenant(self, mock_db):
        mock_db.query.return_value.filter.return_value.all.return_value = []

        resp = _client.get("/vvt/stats")
        assert resp.status_code == 200
        data = resp.json()
        assert data["total"] == 0
        assert data["by_status"] == {}
        assert data["dpia_required_count"] == 0
        assert data["overdue_review_count"] == 0

    def test_stats_with_activities(self, mock_db):
        past = datetime(2025, 1, 1, tzinfo=timezone.utc)
        acts = [
            _make_db_activity(status="DRAFT", business_function="HR", dpia_required=True, next_review_at=past),
            _make_db_activity(status="APPROVED", business_function="IT", dpia_required=False),
            _make_db_activity(status="DRAFT", business_function="HR", dpia_required=False, third_country_transfers=["USA"]),
        ]
        mock_db.query.return_value.filter.return_value.all.return_value = acts

        resp = _client.get("/vvt/stats")
        assert resp.status_code == 200
        data = resp.json()
        assert data["total"] == 3
        assert data["by_status"]["DRAFT"] == 2
        assert data["by_status"]["APPROVED"] == 1
        assert data["by_business_function"]["HR"] == 2
        assert data["by_business_function"]["IT"] == 1
        assert data["dpia_required_count"] == 1
        assert data["third_country_count"] == 1
        assert data["draft_count"] == 2
        assert data["approved_count"] == 1
        assert data["overdue_review_count"] == 1


class TestAuditLogEndpoint:
    """Tests for GET /vvt/audit-log."""

    def test_audit_log_returns_entries(self, mock_db):
        entry = _make_audit_entry(action="CREATE", entity_type="activity")
        mock_db.query.return_value.filter.return_value.order_by.return_value.offset.return_value.limit.return_value.all.return_value = [entry]

        resp = _client.get("/vvt/audit-log")
        assert resp.status_code == 200
        data = resp.json()
        assert len(data) == 1
        assert data[0]["action"] == "CREATE"
        assert data[0]["entity_type"] == "activity"

    def test_audit_log_empty(self, mock_db):
        mock_db.query.return_value.filter.return_value.order_by.return_value.offset.return_value.limit.return_value.all.return_value = []

        resp = _client.get("/vvt/audit-log")
        assert resp.status_code == 200
        assert resp.json() == []

    def test_audit_log_pagination_params(self, mock_db):
        mock_db.query.return_value.filter.return_value.order_by.return_value.offset.return_value.limit.return_value.all.return_value = []

        resp = _client.get("/vvt/audit-log?limit=10&offset=20")
        assert resp.status_code == 200


class TestVersioningEndpoints:
    """Tests for GET /vvt/activities/{id}/versions and /versions/{v}."""

    @patch("compliance.api.versioning_utils.list_versions")
    def test_list_versions_returns_list(self, mock_list_versions, mock_db):
        act_id = str(uuid.uuid4())
        mock_list_versions.return_value = [
            {"id": str(uuid.uuid4()), "version_number": 2, "status": "draft",
             "change_summary": "Updated name", "changed_sections": [],
             "created_by": "admin", "approved_by": None, "approved_at": None,
             "created_at": "2026-01-15T10:00:00"},
            {"id": str(uuid.uuid4()), "version_number": 1, "status": "draft",
             "change_summary": "Initial", "changed_sections": [],
             "created_by": "system", "approved_by": None, "approved_at": None,
             "created_at": "2026-01-14T09:00:00"},
        ]

        resp = _client.get(f"/vvt/activities/{act_id}/versions")
        assert resp.status_code == 200
        data = resp.json()
        assert len(data) == 2
        assert data[0]["version_number"] == 2
        assert data[1]["version_number"] == 1

    @patch("compliance.api.versioning_utils.list_versions")
    def test_list_versions_empty(self, mock_list_versions, mock_db):
        act_id = str(uuid.uuid4())
        mock_list_versions.return_value = []

        resp = _client.get(f"/vvt/activities/{act_id}/versions")
        assert resp.status_code == 200
        assert resp.json() == []

    @patch("compliance.api.versioning_utils.get_version")
    def test_get_specific_version(self, mock_get_version, mock_db):
        act_id = str(uuid.uuid4())
        mock_get_version.return_value = {
            "id": str(uuid.uuid4()),
            "version_number": 1,
            "status": "approved",
            "snapshot": {"name": "Test", "status": "APPROVED"},
            "change_summary": "Initial version",
            "changed_sections": ["name", "status"],
            "created_by": "admin",
            "approved_by": "dpo",
            "approved_at": "2026-01-16T12:00:00",
            "created_at": "2026-01-15T10:00:00",
        }

        resp = _client.get(f"/vvt/activities/{act_id}/versions/1")
        assert resp.status_code == 200
        data = resp.json()
        assert data["version_number"] == 1
        assert data["snapshot"]["name"] == "Test"
        assert data["approved_by"] == "dpo"

    @patch("compliance.api.versioning_utils.get_version")
    def test_get_version_not_found(self, mock_get_version, mock_db):
        act_id = str(uuid.uuid4())
        mock_get_version.return_value = None

        resp = _client.get(f"/vvt/activities/{act_id}/versions/999")
        assert resp.status_code == 404
        assert "not found" in resp.json()["detail"].lower()


class TestExportCsvEdgeCases:
    """Additional edge cases for CSV export helper."""

    def _collect_csv_body(self, response) -> str:
        import asyncio
        async def _read():
            chunks = []
            async for chunk in response.body_iterator:
                chunks.append(chunk)
            return ''.join(chunks)
        return asyncio.get_event_loop().run_until_complete(_read())

    def test_export_csv_with_third_country_transfers(self):
        from compliance.api.vvt_routes import _export_csv
        act = _make_db_activity(
            third_country_transfers=["USA", "China"],
            vvt_id="VVT-TC-001",
            name="Third Country Test",
        )
        response = _export_csv([act])
        text = self._collect_csv_body(response)
        assert "Ja" in text  # third_country_transfers truthy -> "Ja"

    def test_export_csv_no_third_country_transfers(self):
        from compliance.api.vvt_routes import _export_csv
        act = _make_db_activity(
            third_country_transfers=[],
            vvt_id="VVT-NTC-001",
            name="No Third Country",
        )
        response = _export_csv([act])
        text = self._collect_csv_body(response)
        assert "Nein" in text  # empty list -> "Nein"

    def test_export_csv_multiple_activities(self):
        from compliance.api.vvt_routes import _export_csv
        acts = [
            _make_db_activity(vvt_id="VVT-M-001", name="First"),
            _make_db_activity(vvt_id="VVT-M-002", name="Second"),
            _make_db_activity(vvt_id="VVT-M-003", name="Third"),
        ]
        response = _export_csv(acts)
        text = self._collect_csv_body(response)
        lines = text.strip().split('\n')
        # 1 header + 3 data rows
        assert len(lines) == 4
        assert "VVT-M-001" in lines[1]
        assert "VVT-M-002" in lines[2]
        assert "VVT-M-003" in lines[3]

    def test_export_csv_content_disposition_filename(self):
        from compliance.api.vvt_routes import _export_csv
        response = _export_csv([])
        assert "vvt_export_" in response.headers.get("content-disposition", "")
        assert ".csv" in response.headers.get("content-disposition", "")
