from django.db import transaction
from django.utils import timezone

from api.models import IntegrationOutbox


def replay_event(*, event: IntegrationOutbox, actor_id: int | None, reason: str) -> IntegrationOutbox:
    if not reason.strip():
        raise ValueError("A replay reason is required")
    with transaction.atomic():
        original = IntegrationOutbox.objects.select_for_update().get(pk=event.pk)
        if original.status != IntegrationOutbox.Status.DEAD_LETTER:
            raise ValueError("Only dead-letter events may be replayed")
        members = list(
            IntegrationOutbox.objects.select_for_update().filter(
                source_scope=original.source_scope,
                transport_sequence=original.transport_sequence,
                change_set_id=original.change_set_id,
            )
        )
        if not members or any(
            member.status != IntegrationOutbox.Status.DEAD_LETTER for member in members
        ):
            raise ValueError("The complete dead-letter change set must be replayed together")
        # Retry the same immutable transaction ID and source sequence. Creating
        # a later replacement would allow intervening global sequences to overtake it.
        IntegrationOutbox.objects.filter(pk__in=[member.pk for member in members]).update(
            status=IntegrationOutbox.Status.RETRY,
            attempts=0,
            next_attempt_at=timezone.now(),
            claimed_at=None,
            dead_letter_at=None,
            last_error=None,
            replay_requested_by=actor_id,
            replay_reason=reason.strip(),
        )
        original.refresh_from_db()
        return original
