"""Tests for Document Versioning (Phase 3).

Verifies:
- versioning_utils: create_version_snapshot, list_versions, get_version
- VERSION_TABLES mapping is correct
- Version endpoints are registered on all 5 route files
"""

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

from compliance.api.versioning_utils import (
    VERSION_TABLES,
    create_version_snapshot,
    list_versions,
    get_version,
)

TENANT = "9282a473-5c95-4b3a-bf78-0ecc0ec71d3e"
DOC_ID = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"


# =============================================================================
# VERSION_TABLES mapping
# =============================================================================

class TestVersionTablesMapping:
    def test_all_5_doc_types(self):
        assert "dsfa" in VERSION_TABLES
        assert "vvt_activity" in VERSION_TABLES
        assert "tom" in VERSION_TABLES
        assert "loeschfristen" in VERSION_TABLES
        assert "obligation" in VERSION_TABLES
        assert len(VERSION_TABLES) == 5

    def test_dsfa_mapping(self):
        table, fk, source = VERSION_TABLES["dsfa"]
        assert table == "compliance_dsfa_versions"
        assert fk == "dsfa_id"
        assert source == "compliance_dsfas"

    def test_vvt_mapping(self):
        table, fk, source = VERSION_TABLES["vvt_activity"]
        assert table == "compliance_vvt_activity_versions"
        assert fk == "activity_id"
        assert source == "compliance_vvt_activities"

    def test_tom_mapping(self):
        table, fk, source = VERSION_TABLES["tom"]
        assert table == "compliance_tom_versions"
        assert fk == "measure_id"
        assert source == "compliance_tom_measures"

    def test_loeschfristen_mapping(self):
        table, fk, source = VERSION_TABLES["loeschfristen"]
        assert table == "compliance_loeschfristen_versions"
        assert fk == "policy_id"
        assert source == "compliance_loeschfristen"

    def test_obligation_mapping(self):
        table, fk, source = VERSION_TABLES["obligation"]
        assert table == "compliance_obligation_versions"
        assert fk == "obligation_id"
        assert source == "compliance_obligations"


# =============================================================================
# create_version_snapshot
# =============================================================================

class TestCreateVersionSnapshot:
    def test_invalid_doc_type_raises(self):
        db = MagicMock()
        with pytest.raises(ValueError, match="Unknown document type"):
            create_version_snapshot(db, "invalid_type", DOC_ID, TENANT, {"data": 1})

    def test_creates_version_with_correct_params(self):
        db = MagicMock()

        # Mock: MAX(version_number) returns 0 (first version)
        max_result = MagicMock()
        max_result.scalar.return_value = 0

        # Mock: INSERT RETURNING
        insert_result = MagicMock()
        insert_result.fetchone.return_value = (
            "new-uuid",
            1,
            datetime(2026, 3, 7, 12, 0, 0),
        )

        # Mock: UPDATE (returns nothing)
        update_result = MagicMock()

        db.execute.side_effect = [max_result, insert_result, update_result]

        result = create_version_snapshot(
            db, "dsfa", DOC_ID, TENANT,
            snapshot={"title": "Test DSFA"},
            change_summary="Initial version",
            created_by="test-user",
        )

        assert result["version_number"] == 1
        assert result["id"] == "new-uuid"
        assert db.execute.call_count == 3

    def test_increments_version_number(self):
        db = MagicMock()

        # MAX returns 2 (existing 2 versions)
        max_result = MagicMock()
        max_result.scalar.return_value = 2

        insert_result = MagicMock()
        insert_result.fetchone.return_value = ("uuid-3", 3, datetime(2026, 3, 7))

        update_result = MagicMock()
        db.execute.side_effect = [max_result, insert_result, update_result]

        result = create_version_snapshot(
            db, "vvt_activity", DOC_ID, TENANT,
            snapshot={"name": "Activity"},
        )
        assert result["version_number"] == 3


# =============================================================================
# list_versions
# =============================================================================

class TestListVersions:
    def test_invalid_doc_type_raises(self):
        db = MagicMock()
        with pytest.raises(ValueError, match="Unknown document type"):
            list_versions(db, "invalid", DOC_ID, TENANT)

    def test_returns_formatted_list(self):
        db = MagicMock()
        mock_result = MagicMock()
        mock_result.fetchall.return_value = [
            ("uuid-1", 1, "draft", "Initial", [], "system", None, None, datetime(2026, 3, 1)),
            ("uuid-2", 2, "approved", "Updated measures", ["section3"], "admin", "dpo", datetime(2026, 3, 5), datetime(2026, 3, 2)),
        ]
        db.execute.return_value = mock_result

        result = list_versions(db, "tom", DOC_ID, TENANT)
        assert len(result) == 2
        assert result[0]["version_number"] == 1
        assert result[0]["status"] == "draft"
        assert result[1]["version_number"] == 2
        assert result[1]["approved_by"] == "dpo"

    def test_empty_list(self):
        db = MagicMock()
        mock_result = MagicMock()
        mock_result.fetchall.return_value = []
        db.execute.return_value = mock_result

        result = list_versions(db, "obligation", DOC_ID, TENANT)
        assert result == []


# =============================================================================
# get_version
# =============================================================================

class TestGetVersion:
    def test_invalid_doc_type_raises(self):
        db = MagicMock()
        with pytest.raises(ValueError, match="Unknown document type"):
            get_version(db, "invalid", DOC_ID, 1, TENANT)

    def test_returns_version_with_snapshot(self):
        db = MagicMock()
        mock_result = MagicMock()
        mock_result.fetchone.return_value = (
            "uuid-1", 1, "draft", {"title": "Test", "status": "draft"},
            "Initial version", ["section1"], "system", None, None, datetime(2026, 3, 1),
        )
        db.execute.return_value = mock_result

        result = get_version(db, "loeschfristen", DOC_ID, 1, TENANT)
        assert result is not None
        assert result["version_number"] == 1
        assert result["snapshot"]["title"] == "Test"
        assert result["change_summary"] == "Initial version"

    def test_returns_none_for_missing(self):
        db = MagicMock()
        mock_result = MagicMock()
        mock_result.fetchone.return_value = None
        db.execute.return_value = mock_result

        result = get_version(db, "dsfa", DOC_ID, 99, TENANT)
        assert result is None


# =============================================================================
# Route Registration Tests
# =============================================================================

class TestVersionEndpointsRegistered:
    """Verify all 5 route files have version endpoints."""

    def _has_route(self, router, suffix):
        return any(r.path.endswith(suffix) for r in router.routes)

    def test_dsfa_has_version_routes(self):
        from compliance.api.dsfa_routes import router
        assert self._has_route(router, "/versions")
        assert self._has_route(router, "/versions/{version_number}")

    def test_vvt_has_version_routes(self):
        from compliance.api.vvt_routes import router
        assert self._has_route(router, "/versions")
        assert self._has_route(router, "/versions/{version_number}")

    def test_tom_has_version_routes(self):
        from compliance.api.tom_routes import router
        assert self._has_route(router, "/versions")
        assert self._has_route(router, "/versions/{version_number}")

    def test_loeschfristen_has_version_routes(self):
        from compliance.api.loeschfristen_routes import router
        assert self._has_route(router, "/versions")
        assert self._has_route(router, "/versions/{version_number}")

    def test_obligation_has_version_routes(self):
        from compliance.api.obligation_routes import router
        assert self._has_route(router, "/versions")
        assert self._has_route(router, "/versions/{version_number}")
