"""
StripeWebhookEvent model for django_stripe_billing.

Persists every incoming Stripe webhook event for idempotency and auditing.
The unique constraint on ``stripe_event_id`` prevents duplicate processing:
the receiver attempts an INSERT; if it raises IntegrityError the event was
already seen and can be safely skipped.
"""
from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

WEBHOOK_STATUS_PENDING = "pending"
WEBHOOK_STATUS_PROCESSING = "processing"
WEBHOOK_STATUS_SUCCESS = "success"
WEBHOOK_STATUS_ERROR = "error"
WEBHOOK_STATUS_SKIPPED = "skipped"

WEBHOOK_STATUS_CHOICES = [
    (WEBHOOK_STATUS_PENDING, _("Pending")),
    (WEBHOOK_STATUS_PROCESSING, _("Processing")),
    (WEBHOOK_STATUS_SUCCESS, _("Success")),
    (WEBHOOK_STATUS_ERROR, _("Error")),
    (WEBHOOK_STATUS_SKIPPED, _("Skipped")),
]


class StripeWebhookEvent(models.Model):
    """
    Persists every incoming Stripe webhook event for idempotency and audit.

    Usage::

        from django_stripe_billing.models import StripeWebhookEvent

    The unique constraint on ``stripe_event_id`` prevents duplicate processing:
    the webhook receiver attempts an INSERT; if it raises ``IntegrityError``
    the event was already seen and is safely skipped.
    """

    stripe_event_id = models.CharField(
        max_length=255,
        unique=True,
        db_index=True,
        help_text=_(
            "Stripe event ID (evt_...). Unique constraint enforces idempotency."
        ),
    )
    event_type = models.CharField(
        max_length=100,
        help_text=_("Stripe event type, e.g. invoice.payment_succeeded"),
    )
    api_version = models.CharField(
        max_length=20,
        blank=True,
        default="",
        help_text=_("Stripe API version from the event."),
    )
    livemode = models.BooleanField(
        default=True,
        help_text=_("Whether the event was produced in live mode."),
    )
    payload = models.TextField(
        help_text=_("Raw JSON payload (truncated to 10 000 chars)."),
    )
    status = models.CharField(
        max_length=20,
        choices=WEBHOOK_STATUS_CHOICES,
        default=WEBHOOK_STATUS_PENDING,
        db_index=True,
    )
    attempts = models.PositiveSmallIntegerField(
        default=0,
        help_text=_("Number of processing attempts."),
    )
    error_message = models.TextField(
        blank=True,
        default="",
        help_text=_("Error details if status is error."),
    )
    created_at = models.DateTimeField(auto_now_add=True)
    processed_at = models.DateTimeField(null=True, blank=True)

    class Meta:
        verbose_name = _("Stripe Webhook Event")
        verbose_name_plural = _("Stripe Webhook Events")
        ordering = ["-created_at"]
        indexes = [
            models.Index(fields=["event_type", "status"]),
            models.Index(fields=["created_at"]),
        ]

    def __str__(self) -> str:
        return f"{self.stripe_event_id} ({self.event_type}) — {self.status}"

    # ------------------------------------------------------------------
    # State transitions
    # ------------------------------------------------------------------

    def mark_processing(self) -> None:
        self.status = WEBHOOK_STATUS_PROCESSING
        self.attempts += 1
        self.save(update_fields=["status", "attempts"])

    def mark_success(self) -> None:
        self.status = WEBHOOK_STATUS_SUCCESS
        self.processed_at = timezone.now()
        self.save(update_fields=["status", "processed_at"])

    def mark_error(self, message: str) -> None:
        self.status = WEBHOOK_STATUS_ERROR
        self.error_message = message[:5000]
        self.processed_at = timezone.now()
        self.save(update_fields=["status", "error_message", "processed_at"])

    def mark_skipped(self, reason: str = "") -> None:
        self.status = WEBHOOK_STATUS_SKIPPED
        self.error_message = reason[:5000]
        self.processed_at = timezone.now()
        self.save(update_fields=["status", "error_message", "processed_at"])
