"""Data retention enforcement service.

⚠️ AUTO-GENERATED BY PRISM — DO NOT EDIT
This file is regenerated on every `prisme generate`.

Implements automatic data expiry and deletion based on retention policies
defined in the Prism specification.
"""

from __future__ import annotations

import logging
from datetime import datetime, timedelta, timezone
from typing import Any

from sqlalchemy import delete as sa_delete, select, func
from sqlalchemy.ext.asyncio import AsyncSession

from {{ package_name }}.privacy.audit_service import AuditService
{% for model in retention_models %}
from {{ package_name }}.models.{{ model.snake_name }} import {{ model.name }}
{% endfor %}

logger = logging.getLogger(__name__)


class RetentionService:
    """Enforces data retention policies by deleting expired records.

    Each model with a retention policy is checked against its configured
    retention_days. Records older than the threshold are purged.
    """

    def __init__(self, session: AsyncSession) -> None:
        self.session = session
        self.audit = AuditService(session)

    async def enforce_all(self) -> dict[str, dict[str, Any]]:
        """Run retention enforcement for all configured models.

        Returns:
            Summary of records deleted per model.
        """
        results: dict[str, dict[str, Any]] = {}
{% for model in retention_models %}
        results["{{ model.snake_name }}"] = await self._enforce_{{ model.snake_name }}()
{% endfor %}
        return results
{% for model in retention_models %}

    async def _enforce_{{ model.snake_name }}(self) -> dict[str, Any]:
        """Enforce retention policy for {{ model.name }}.

        Policy: {{ model.retention_days }} days retention.
{% if model.soft_delete_first %}
        Strategy: soft-delete first, then hard-delete after retention period.
{% else %}
        Strategy: hard-delete after retention period.
{% endif %}
{% if model.archive_before_delete %}
        Records are logged to the audit trail before deletion.
{% endif %}
        """
        cutoff = datetime.now(timezone.utc) - timedelta(days={{ model.retention_days }})
{% if model.soft_delete_first %}
        # Find records that were soft-deleted before the cutoff
        stmt = select({{ model.name }}).where(
            {{ model.name }}.deleted_at.isnot(None),
            {{ model.name }}.deleted_at < cutoff,
        )
{% else %}
        # Find records created before the cutoff
        stmt = select({{ model.name }}).where(
            {{ model.name }}.created_at < cutoff,
        )
{% endif %}
        result = await self.session.execute(stmt)
        expired_records = result.scalars().all()

        if not expired_records:
            return {"deleted": 0, "cutoff": cutoff.isoformat()}
{% if model.archive_before_delete %}

        # Log each deletion to the audit trail
        for record in expired_records:
            await self.audit.log(
                operation="retention_delete",
                model_name="{{ model.name }}",
                record_id=str(record.id),
                details="Retention policy: {{ model.retention_days }} days expired",
            )
{% endif %}

        # Hard-delete expired records
{% if model.soft_delete_first %}
        delete_stmt = sa_delete({{ model.name }}).where(
            {{ model.name }}.deleted_at.isnot(None),
            {{ model.name }}.deleted_at < cutoff,
        )
{% else %}
        delete_stmt = sa_delete({{ model.name }}).where(
            {{ model.name }}.created_at < cutoff,
        )
{% endif %}
        delete_result = await self.session.execute(delete_stmt)
        deleted_count = delete_result.rowcount

        logger.info(
            "Retention: deleted %d expired %s records (cutoff: %s)",
            deleted_count,
            "{{ model.name }}",
            cutoff.isoformat(),
        )

        return {"deleted": deleted_count, "cutoff": cutoff.isoformat()}
{% endfor %}

    async def get_retention_report(self) -> list[dict[str, Any]]:
        """Generate a report of records approaching retention expiry.

        Returns:
            List of model summaries with counts of records nearing expiry.
        """
        report: list[dict[str, Any]] = []
        now = datetime.now(timezone.utc)
{% for model in retention_models %}

        # {{ model.name }}: {{ model.retention_days }}-day retention
        cutoff_{{ model.snake_name }} = now - timedelta(days={{ model.retention_days }})
        warning_{{ model.snake_name }} = now - timedelta(days=max(1, {{ model.retention_days }} - 30))
{% if model.soft_delete_first %}
        expired_count = await self.session.scalar(
            select(func.count()).select_from({{ model.name }}).where(
                {{ model.name }}.deleted_at.isnot(None),
                {{ model.name }}.deleted_at < cutoff_{{ model.snake_name }},
            )
        )
        expiring_soon_count = await self.session.scalar(
            select(func.count()).select_from({{ model.name }}).where(
                {{ model.name }}.deleted_at.isnot(None),
                {{ model.name }}.deleted_at >= cutoff_{{ model.snake_name }},
                {{ model.name }}.deleted_at < warning_{{ model.snake_name }},
            )
        )
{% else %}
        expired_count = await self.session.scalar(
            select(func.count()).select_from({{ model.name }}).where(
                {{ model.name }}.created_at < cutoff_{{ model.snake_name }},
            )
        )
        expiring_soon_count = await self.session.scalar(
            select(func.count()).select_from({{ model.name }}).where(
                {{ model.name }}.created_at >= cutoff_{{ model.snake_name }},
                {{ model.name }}.created_at < warning_{{ model.snake_name }},
            )
        )
{% endif %}
        report.append({
            "model": "{{ model.name }}",
            "retention_days": {{ model.retention_days }},
            "expired_records": expired_count or 0,
            "expiring_within_30_days": expiring_soon_count or 0,
        })
{% endfor %}
        return report
