import uuid

from django.db import models


class IntegrationAggregateVersion(models.Model):
    """Serializes canonical event versions for one source aggregate."""

    aggregate_type = models.CharField(max_length=64)
    aggregate_id = models.CharField(max_length=190)
    version = models.PositiveBigIntegerField(default=0)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "integration_aggregate_version"
        constraints = [
            models.UniqueConstraint(
                fields=["aggregate_type", "aggregate_id"],
                name="uq_integration_aggregate_version",
            )
        ]


class IntegrationTransportCursor(models.Model):
    """Serializes commit-ordered transport sequences for one source scope."""

    source_scope = models.CharField(max_length=190, unique=True)
    last_sequence = models.PositiveBigIntegerField(default=0)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "integration_transport_cursor"


class IntegrationOutbox(models.Model):
    class Status(models.TextChoices):
        PENDING = "pending", "Pending"
        PUBLISHING = "publishing", "Publishing"
        RETRY = "retry", "Retry"
        PUBLISHED = "published", "Published"
        DEAD_LETTER = "dead_letter", "Dead letter"
        SUPERSEDED = "superseded", "Superseded by replay"

    event_id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)
    schema_version = models.CharField(max_length=32, default="2")
    event_type = models.CharField(max_length=120)
    aggregate_type = models.CharField(max_length=64)
    aggregate_id = models.CharField(max_length=190)
    event_version = models.PositiveBigIntegerField()
    source_scope = models.CharField(max_length=190, default="default", db_index=True)
    transport_sequence = models.PositiveBigIntegerField(default=0, db_index=True)
    transaction_index = models.PositiveIntegerField(default=1)
    transaction_count = models.PositiveIntegerField(default=1)
    transaction_finalized = models.BooleanField(default=True, db_index=True)
    ordering_key = models.CharField(max_length=255, db_index=True)
    change_set_id = models.UUIDField(default=uuid.uuid4, db_index=True)
    origin = models.CharField(max_length=64, default="timetabler")
    correlation_id = models.CharField(max_length=190, null=True, blank=True, db_index=True)
    causation_id = models.CharField(max_length=190, null=True, blank=True)
    request_id = models.CharField(max_length=190, null=True, blank=True, db_index=True)
    actor_id = models.BigIntegerField(null=True, blank=True)
    payload = models.JSONField(default=dict)
    status = models.CharField(
        max_length=24,
        choices=Status.choices,
        default=Status.PENDING,
        db_index=True,
    )
    attempts = models.PositiveIntegerField(default=0)
    next_attempt_at = models.DateTimeField(null=True, blank=True, db_index=True)
    last_error = models.TextField(null=True, blank=True)
    claimed_at = models.DateTimeField(null=True, blank=True)
    published_at = models.DateTimeField(null=True, blank=True)
    dead_letter_at = models.DateTimeField(null=True, blank=True, db_index=True)
    superseded_at = models.DateTimeField(null=True, blank=True)
    replay_of = models.ForeignKey(
        "self",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="replays",
    )
    replay_requested_by = models.BigIntegerField(null=True, blank=True)
    replay_reason = models.TextField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True, db_index=True)

    class Meta:
        db_table = "integration_outbox"
        constraints = [
            models.UniqueConstraint(
                fields=["aggregate_type", "aggregate_id", "event_version"],
                name="uq_integration_outbox_aggregate_version",
            ),
            models.UniqueConstraint(
                fields=["source_scope", "change_set_id", "transaction_index"],
                name="uq_outbox_scope_change_index",
            ),
        ]
        indexes = [
            models.Index(
                fields=["status", "next_attempt_at", "created_at"],
                name="ix_outbox_eligible",
            ),
            models.Index(
                fields=["aggregate_type", "aggregate_id", "event_version"],
                name="ix_outbox_aggregate_order",
            ),
            models.Index(
                fields=["status", "created_at"],
                name="ix_outbox_state_created",
            ),
            models.Index(
                fields=["source_scope", "transport_sequence", "status"],
                name="ix_outbox_transport_order",
            ),
        ]

    def __str__(self):
        return f"{self.event_type}:{self.aggregate_type}:{self.aggregate_id}:v{self.event_version}"


class IntegrationPublisherState(models.Model):
    """Non-secret operational heartbeat for the single ordered publisher."""

    source_scope = models.CharField(max_length=190, unique=True)
    status = models.CharField(max_length=32, default="starting")
    heartbeat_at = models.DateTimeField(null=True, blank=True)
    last_success_at = models.DateTimeField(null=True, blank=True)
    last_published_sequence = models.PositiveBigIntegerField(default=0)
    last_error = models.TextField(null=True, blank=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "integration_publisher_state"
