"""Tests for GDPR privacy specification models."""

from __future__ import annotations

import pytest

from prisme.spec.privacy import (
    DataClassification,
    DataSubjectRightsConfig,
    FieldPrivacyConfig,
    GDPRModelConfig,
    LegalBasis,
    PrivacyConfig,
    RetentionPolicy,
)


class TestDataClassification:
    """Tests for DataClassification enum."""

    def test_values(self):
        assert DataClassification.PUBLIC == "public"
        assert DataClassification.INTERNAL == "internal"
        assert DataClassification.CONFIDENTIAL == "confidential"
        assert DataClassification.HIGHLY_CONFIDENTIAL == "highly_confidential"


class TestLegalBasis:
    """Tests for LegalBasis enum."""

    def test_values(self):
        assert LegalBasis.CONSENT == "consent"
        assert LegalBasis.CONTRACT == "contract"
        assert LegalBasis.LEGAL_OBLIGATION == "legal_obligation"
        assert LegalBasis.LEGITIMATE_INTERESTS == "legitimate_interests"


class TestFieldPrivacyConfig:
    """Tests for FieldPrivacyConfig model."""

    def test_defaults(self):
        config = FieldPrivacyConfig()
        assert config.classification == DataClassification.INTERNAL
        assert config.is_pii is False
        assert config.redact_in_logs is False
        assert config.audit_access is False
        assert config.encrypt_at_rest is False

    def test_full_config(self):
        config = FieldPrivacyConfig(
            classification=DataClassification.HIGHLY_CONFIDENTIAL,
            is_pii=True,
            redact_in_logs=True,
            audit_access=True,
            encrypt_at_rest=True,
        )
        assert config.classification == DataClassification.HIGHLY_CONFIDENTIAL
        assert config.is_pii is True
        assert config.redact_in_logs is True

    def test_rejects_extra_fields(self):
        with pytest.raises(ValueError):
            FieldPrivacyConfig(classification=DataClassification.PUBLIC, unknown_field="x")


class TestRetentionPolicy:
    """Tests for RetentionPolicy model."""

    def test_basic(self):
        policy = RetentionPolicy(retention_days=365)
        assert policy.retention_days == 365
        assert policy.auto_delete is False
        assert policy.archive_before_delete is True
        assert policy.soft_delete_first is True

    def test_auto_delete(self):
        policy = RetentionPolicy(
            retention_days=90,
            auto_delete=True,
            soft_delete_first=False,
        )
        assert policy.auto_delete is True
        assert policy.soft_delete_first is False

    def test_retention_days_must_be_positive(self):
        with pytest.raises(ValueError):
            RetentionPolicy(retention_days=0)

    def test_retention_days_negative_rejected(self):
        with pytest.raises(ValueError):
            RetentionPolicy(retention_days=-1)


class TestDataSubjectRightsConfig:
    """Tests for DataSubjectRightsConfig model."""

    def test_defaults(self):
        rights = DataSubjectRightsConfig()
        assert rights.right_to_access is True
        assert rights.right_to_erasure is True
        assert rights.right_to_rectification is True
        assert rights.right_to_portability is True
        assert rights.right_to_restrict_processing is False
        assert rights.export_formats == ["json", "csv"]

    def test_custom_export_formats(self):
        rights = DataSubjectRightsConfig(export_formats=["json", "csv", "xml"])
        assert "xml" in rights.export_formats

    def test_invalid_export_format_rejected(self):
        with pytest.raises(Exception, match="Unsupported export format"):
            DataSubjectRightsConfig(export_formats=["json", "pdf"])


class TestGDPRModelConfig:
    """Tests for GDPRModelConfig model."""

    def test_defaults(self):
        config = GDPRModelConfig()
        assert config.is_personal_data is False
        assert config.legal_basis == LegalBasis.LEGITIMATE_INTERESTS
        assert config.purpose == ""
        assert config.retention is None
        assert config.anonymize_on_delete is False

    def test_full_config(self):
        config = GDPRModelConfig(
            is_personal_data=True,
            legal_basis=LegalBasis.CONTRACT,
            purpose="Customer relationship management",
            retention=RetentionPolicy(retention_days=730),
            anonymize_on_delete=True,
            data_subject_rights=DataSubjectRightsConfig(
                right_to_restrict_processing=True,
            ),
        )
        assert config.is_personal_data is True
        assert config.legal_basis == LegalBasis.CONTRACT
        assert config.retention is not None
        assert config.retention.retention_days == 730
        assert config.data_subject_rights.right_to_restrict_processing is True


class TestPrivacyConfig:
    """Tests for project-level PrivacyConfig model."""

    def test_defaults(self):
        config = PrivacyConfig()
        assert config.enabled is False
        assert config.organization_name == ""
        assert config.dpo_email == ""
        assert config.generate_audit_log is True
        assert config.generate_compliance_docs is True
        assert config.generate_retention_jobs is True
        assert config.nis2_enabled is False
        assert config.subprocessors == []

    def test_full_config(self):
        config = PrivacyConfig(
            enabled=True,
            organization_name="Acme Corp",
            dpo_email="dpo@acme.com",
            privacy_policy_url="https://acme.com/privacy",
            data_processing_region="EU",
            nis2_enabled=True,
            nis2_sector="digital_infrastructure",
            nis2_entity_type="essential",
            subprocessors=["AWS", "Stripe"],
        )
        assert config.enabled is True
        assert config.organization_name == "Acme Corp"
        assert config.nis2_entity_type == "essential"
        assert len(config.subprocessors) == 2

    def test_invalid_nis2_entity_type(self):
        with pytest.raises(Exception, match="NIS2 entity type"):
            PrivacyConfig(nis2_entity_type="unknown")


class TestFieldSpecPrivacyIntegration:
    """Tests that FieldSpec accepts privacy config."""

    def test_field_with_privacy(self):
        from prisme.spec.fields import FieldSpec, FieldType

        field = FieldSpec(
            name="email",
            type=FieldType.STRING,
            privacy=FieldPrivacyConfig(
                classification=DataClassification.CONFIDENTIAL,
                is_pii=True,
                redact_in_logs=True,
            ),
        )
        assert field.privacy is not None
        assert field.privacy.is_pii is True
        assert field.privacy.classification == DataClassification.CONFIDENTIAL

    def test_field_without_privacy(self):
        from prisme.spec.fields import FieldSpec, FieldType

        field = FieldSpec(name="status", type=FieldType.STRING)
        assert field.privacy is None


class TestModelSpecGDPRIntegration:
    """Tests that ModelSpec accepts GDPR config."""

    def test_model_with_gdpr(self):
        from prisme.spec.fields import FieldSpec, FieldType
        from prisme.spec.model import ModelSpec

        model = ModelSpec(
            name="Customer",
            fields=[FieldSpec(name="name", type=FieldType.STRING)],
            gdpr=GDPRModelConfig(
                is_personal_data=True,
                legal_basis=LegalBasis.CONTRACT,
                retention=RetentionPolicy(retention_days=365),
            ),
        )
        assert model.gdpr is not None
        assert model.gdpr.is_personal_data is True
        assert model.gdpr.retention.retention_days == 365

    def test_model_without_gdpr(self):
        from prisme.spec.fields import FieldSpec, FieldType
        from prisme.spec.model import ModelSpec

        model = ModelSpec(
            name="Product",
            fields=[FieldSpec(name="title", type=FieldType.STRING)],
        )
        assert model.gdpr is None


class TestProjectSpecPrivacyIntegration:
    """Tests that ProjectSpec accepts privacy config."""

    def test_project_with_privacy(self):
        from prisme.spec.project import ProjectSpec

        project = ProjectSpec(
            name="test-app",
            privacy=PrivacyConfig(
                enabled=True,
                organization_name="Test Corp",
                dpo_email="dpo@test.com",
            ),
        )
        assert project.privacy.enabled is True
        assert project.privacy.organization_name == "Test Corp"

    def test_project_default_privacy(self):
        from prisme.spec.project import ProjectSpec

        project = ProjectSpec(name="test-app")
        assert project.privacy.enabled is False
