"""GDPR privacy generator for Prism.

Generates audit logging, data export, data deletion, retention enforcement,
and privacy API routes for models marked with GDPR configuration.
"""

from __future__ import annotations

from pathlib import Path
from typing import Any

from prisme.generators.base import GeneratedFile, GeneratorBase
from prisme.spec.stack import FileStrategy
from prisme.utils.case_conversion import to_snake_case
from prisme.utils.template_engine import TemplateRenderer


class PrivacyGenerator(GeneratorBase):
    """Generates GDPR privacy infrastructure.

    Creates audit log model, services for data export/deletion/retention,
    and FastAPI routes for privacy operations.

    Only generates files when privacy.enabled=True in the project spec.
    """

    REQUIRED_TEMPLATES = [
        "backend/privacy/audit_log_model.py.jinja2",
        "backend/privacy/audit_service.py.jinja2",
        "backend/privacy/data_export_service.py.jinja2",
        "backend/privacy/data_deletion_service.py.jinja2",
        "backend/privacy/retention_service.py.jinja2",
        "backend/privacy/privacy_routes.py.jinja2",
        "backend/privacy/privacy_init.py.jinja2",
    ]

    def __init__(self, *args: Any, **kwargs: Any) -> None:
        super().__init__(*args, **kwargs)

        privacy_config = self._get_privacy_config()
        if not privacy_config or not privacy_config.enabled:
            self.skip_generation = True
            return

        self.skip_generation = False
        self.privacy_config = privacy_config
        self.renderer = TemplateRenderer()
        self.renderer.validate_templates_exist(self.REQUIRED_TEMPLATES)

        backend_base = Path(self.generator_config.backend_output)
        package_name = self.get_package_name()
        package_base = backend_base / package_name
        self.privacy_path = package_base / "privacy"

    def _get_privacy_config(self) -> Any:
        """Get privacy config from project spec, or None."""
        if self.project_spec and hasattr(self.project_spec, "privacy"):
            return self.project_spec.privacy
        return None

    def _get_personal_data_models(self) -> list[dict[str, Any]]:
        """Collect models marked as personal data stores."""
        models = []
        for model in self.spec.models:
            if model.gdpr and model.gdpr.is_personal_data:
                snake_name = to_snake_case(model.name)
                pii_fields = []
                pii_field_types: dict[str, str] = {}
                fields_with_privacy = []

                for field in model.fields:
                    if field.privacy:
                        fields_with_privacy.append(
                            {
                                "name": field.name,
                                "classification": field.privacy.classification.value,
                                "is_pii": field.privacy.is_pii,
                                "encrypt_at_rest": field.privacy.encrypt_at_rest,
                                "redact_in_logs": field.privacy.redact_in_logs,
                                "audit_access": field.privacy.audit_access,
                            }
                        )
                        if field.privacy.is_pii:
                            pii_fields.append(field.name)
                            pii_field_types[field.name] = field.type.value

                models.append(
                    {
                        "name": model.name,
                        "snake_name": snake_name,
                        "purpose": model.gdpr.purpose,
                        "legal_basis": model.gdpr.legal_basis.value,
                        "pii_fields": pii_fields,
                        "pii_field_types": pii_field_types,
                        "fields_with_privacy": fields_with_privacy,
                        "anonymize_on_delete": model.gdpr.anonymize_on_delete,
                        "retention": model.gdpr.retention,
                    }
                )
        return models

    def _get_retention_models(self) -> list[dict[str, Any]]:
        """Collect models with retention policies."""
        models = []
        for model in self.spec.models:
            if model.gdpr and model.gdpr.retention:
                retention = model.gdpr.retention
                models.append(
                    {
                        "name": model.name,
                        "snake_name": to_snake_case(model.name),
                        "retention_days": retention.retention_days,
                        "auto_delete": retention.auto_delete,
                        "soft_delete_first": retention.soft_delete_first,
                        "archive_before_delete": retention.archive_before_delete,
                    }
                )
        return models

    def _get_supported_formats(self) -> list[str]:
        """Get the union of all export formats across personal data models."""
        formats: set[str] = set()
        for model in self.spec.models:
            if model.gdpr and model.gdpr.is_personal_data:
                formats.update(model.gdpr.data_subject_rights.export_formats)
        return sorted(formats) if formats else ["json", "csv"]

    def _base_context(self) -> dict[str, Any]:
        """Build the base template context."""
        return {
            "package_name": self.get_package_name(),
            "personal_data_models": self._get_personal_data_models(),
            "retention_models": self._get_retention_models(),
            "has_retention": len(self._get_retention_models()) > 0,
            "supported_formats": self._get_supported_formats(),
        }

    def generate_files(self) -> list[GeneratedFile]:
        """Generate all privacy files."""
        if self.skip_generation:
            return []

        ctx = self._base_context()
        files = [
            self._generate_audit_log_model(ctx),
            self._generate_audit_service(ctx),
            self._generate_data_export_service(ctx),
            self._generate_data_deletion_service(ctx),
            self._generate_privacy_routes(ctx),
            self._generate_init(ctx),
        ]

        # Only generate retention service if there are retention policies
        if ctx["has_retention"]:
            files.append(self._generate_retention_service(ctx))

        return files

    def _generate_audit_log_model(self, ctx: dict[str, Any]) -> GeneratedFile:
        content = self.renderer.render_file(
            "backend/privacy/audit_log_model.py.jinja2",
            context=ctx,
        )
        return GeneratedFile(
            path=self.privacy_path / "audit_log_model.py",
            content=content,
            strategy=FileStrategy.ALWAYS_OVERWRITE,
            description="GDPR audit log model",
        )

    def _generate_audit_service(self, ctx: dict[str, Any]) -> GeneratedFile:
        content = self.renderer.render_file(
            "backend/privacy/audit_service.py.jinja2",
            context=ctx,
        )
        return GeneratedFile(
            path=self.privacy_path / "audit_service.py",
            content=content,
            strategy=FileStrategy.ALWAYS_OVERWRITE,
            description="GDPR audit logging service",
        )

    def _generate_data_export_service(self, ctx: dict[str, Any]) -> GeneratedFile:
        content = self.renderer.render_file(
            "backend/privacy/data_export_service.py.jinja2",
            context=ctx,
        )
        return GeneratedFile(
            path=self.privacy_path / "data_export_service.py",
            content=content,
            strategy=FileStrategy.ALWAYS_OVERWRITE,
            description="GDPR data export service",
        )

    def _generate_data_deletion_service(self, ctx: dict[str, Any]) -> GeneratedFile:
        content = self.renderer.render_file(
            "backend/privacy/data_deletion_service.py.jinja2",
            context=ctx,
        )
        return GeneratedFile(
            path=self.privacy_path / "data_deletion_service.py",
            content=content,
            strategy=FileStrategy.ALWAYS_OVERWRITE,
            description="GDPR data deletion service",
        )

    def _generate_retention_service(self, ctx: dict[str, Any]) -> GeneratedFile:
        content = self.renderer.render_file(
            "backend/privacy/retention_service.py.jinja2",
            context=ctx,
        )
        return GeneratedFile(
            path=self.privacy_path / "retention_service.py",
            content=content,
            strategy=FileStrategy.ALWAYS_OVERWRITE,
            description="Data retention enforcement service",
        )

    def _generate_privacy_routes(self, ctx: dict[str, Any]) -> GeneratedFile:
        content = self.renderer.render_file(
            "backend/privacy/privacy_routes.py.jinja2",
            context=ctx,
        )
        return GeneratedFile(
            path=self.privacy_path / "routes.py",
            content=content,
            strategy=FileStrategy.ALWAYS_OVERWRITE,
            description="GDPR privacy API routes",
        )

    def _generate_init(self, ctx: dict[str, Any]) -> GeneratedFile:
        content = self.renderer.render_file(
            "backend/privacy/privacy_init.py.jinja2",
            context=ctx,
        )
        return GeneratedFile(
            path=self.privacy_path / "__init__.py",
            content=content,
            strategy=FileStrategy.ALWAYS_OVERWRITE,
            description="Privacy module init",
        )
