from django.db import models
from django.utils import timezone
from django.conf import settings


class SoftDeleteQuerySet(models.QuerySet):
    """QuerySet that filters out soft-deleted rows by default."""

    def delete(self):
        # Prevent accidental hard deletes through queryset.delete()
        for obj in self:
            obj.delete()

    def hard_delete(self):
        return super().delete()

    def with_deleted(self):
        """Return all rows, including soft-deleted."""
        return super().all()


class SoftDeleteManager(models.Manager):
    """Manager that hides soft-deleted rows by default."""

    def get_queryset(self):
        return SoftDeleteQuerySet(self.model, using=self._db).filter(is_deleted=False)

    def with_deleted(self):
        return SoftDeleteQuerySet(self.model, using=self._db)


class SoftDeletableModel(models.Model):
    """
    Abstract mixin for soft-deletion with retention window.
    Objects are hidden by default via SoftDeleteManager.
    """

    is_deleted = models.BooleanField(default=False, db_index=True)
    deleted_at = models.DateTimeField(null=True, blank=True, db_index=True)
    restore_until = models.DateTimeField(null=True, blank=True, db_index=True)
    delete_reason = models.CharField(max_length=255, null=True, blank=True)
    deleted_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='+',
    )

    objects = SoftDeleteManager()
    all_objects = models.Manager()

    DEFAULT_RETENTION_DAYS = 14

    class Meta:
        abstract = True

    def soft_delete(self, user=None, reason=None, retention_days=None):
        """Mark the instance as deleted with a retention window."""
        if self.is_deleted:
            return
        now = timezone.now()
        if retention_days is None:
            retention_days = getattr(
                getattr(self, 'account', None),
                'deletion_retention_days',
                self.DEFAULT_RETENTION_DAYS,
            )
        self.is_deleted = True
        self.deleted_at = now
        self.restore_until = now + timezone.timedelta(days=retention_days)
        self.deleted_by = user
        if reason:
            self.delete_reason = reason
        self.save(update_fields=['is_deleted', 'deleted_at', 'restore_until', 'deleted_by', 'delete_reason'])

    def restore(self):
        """Restore a soft-deleted instance if within the retention window."""
        if not self.is_deleted:
            return
        self.is_deleted = False
        self.deleted_at = None
        self.restore_until = None
        self.delete_reason = None
        self.deleted_by = None
        self.save(update_fields=['is_deleted', 'deleted_at', 'restore_until', 'delete_reason', 'deleted_by'])

    def delete(self, using=None, keep_parents=False):
        """Override delete to perform a soft delete."""
        self.soft_delete()

    def hard_delete(self, using=None, keep_parents=False):
        """Irrevocably delete the row."""
        return super().delete(using=using, keep_parents=keep_parents)

