"""Service for automatic meeting retention and cleanup."""

from __future__ import annotations

from collections.abc import Callable
from dataclasses import dataclass
from datetime import UTC, datetime, timedelta
from typing import TYPE_CHECKING

from noteflow.infrastructure.logging import get_logger

if TYPE_CHECKING:
    from noteflow.domain.entities import Meeting
    from noteflow.domain.ports.unit_of_work import UnitOfWork

logger = get_logger(__name__)


@dataclass(frozen=True)
class RetentionReport:
    """Result of retention cleanup run.

    Attributes:
        meetings_checked: Number of meetings that matched cutoff criteria.
        meetings_deleted: Number of meetings successfully deleted.
        errors: List of error messages for failed deletions.
    """

    meetings_checked: int
    meetings_deleted: int
    errors: tuple[str, ...]


class RetentionService:
    """Manage automatic deletion of expired meetings.

    Find and delete meetings that have been completed longer than
    the configured retention period.
    """

    def __init__(
        self,
        uow_factory: Callable[[], UnitOfWork],
        retention_days: int,
        enabled: bool = False,
    ) -> None:
        """Initialize retention service.

        Args:
            uow_factory: Factory that returns a fresh UnitOfWork instance per call.
            retention_days: Days to retain completed meetings.
            enabled: Whether retention is enabled.
        """
        self._uow_factory = uow_factory
        self._retention_days = retention_days
        self._enabled = enabled

    @property
    def is_enabled(self) -> bool:
        """Check if retention is enabled."""
        return self._enabled

    @property
    def retention_days(self) -> int:
        """Get configured retention days."""
        return self._retention_days

    @property
    def cutoff_date(self) -> datetime:
        """Calculate cutoff date for retention."""
        return datetime.now(UTC) - timedelta(days=self._retention_days)

    async def find_expired_meetings(self) -> list[Meeting]:
        """Find meetings older than retention period.

        Returns:
            List of meetings eligible for deletion.
        """
        uow = self._uow_factory()
        async with uow:
            return list(await uow.meetings.find_older_than(self.cutoff_date))

    async def run_cleanup(self, dry_run: bool = False) -> RetentionReport:
        """Execute retention cleanup.

        Args:
            dry_run: If True, report but don't delete.

        Returns:
            Report of cleanup results.
        """
        if not self._enabled and not dry_run:
            logger.info("Retention disabled, skipping cleanup")
            return RetentionReport(
                meetings_checked=0,
                meetings_deleted=0,
                errors=(),
            )

        cutoff = self.cutoff_date
        logger.info(
            "Running retention cleanup (dry_run=%s, cutoff=%s)",
            dry_run,
            cutoff.isoformat(),
        )

        expired = await self.find_expired_meetings()
        deleted = 0
        errors: list[str] = []

        for meeting in expired:
            if dry_run:
                logger.info(
                    "Would delete expired meeting: id=%s, ended_at=%s",
                    meeting.id,
                    meeting.ended_at,
                )
                continue

            try:
                # Import here to avoid circular imports
                from noteflow.application.services import MeetingService

                # Use a fresh UnitOfWork instance for each deletion
                meeting_svc = MeetingService(self._uow_factory())
                success = await meeting_svc.delete_meeting(meeting.id)
                if success:
                    deleted += 1
                    logger.info(
                        "Deleted expired meeting: id=%s",
                        meeting.id,
                    )
            except (OSError, RuntimeError) as e:
                error_msg = f"{meeting.id}: {e}"
                errors.append(error_msg)
                logger.warning("Failed to delete meeting %s: %s", meeting.id, e)

        logger.info(
            "Retention cleanup complete: checked=%d, deleted=%d, errors=%d",
            len(expired),
            deleted,
            len(errors),
        )

        return RetentionReport(
            meetings_checked=len(expired),
            meetings_deleted=deleted,
            errors=tuple(errors),
        )
