from django.db import models


class Sequence(models.Model):
    """
    Stores the current sequence value for each FormattedAutoField instance.

    This model is the "source of truth" for sequence counters and uses database
    row-level locking to prevent race conditions when multiple processes/threads
    try to generate IDs simultaneously.

    Each unique field (identified by app_label.model_name.field_name) has its own
    sequence record.
    """

    key = models.CharField(
        max_length=255,
        unique=True,
        help_text="Unique identifier for this sequence in format: app_label.model_name.field_name"
    )

    last_value = models.PositiveIntegerField(
        default=0,
        help_text="The last number handed out by this sequence"
    )

    created_at = models.DateTimeField(
        auto_now_add=True,
        help_text="When this sequence was first created"
    )

    updated_at = models.DateTimeField(
        auto_now=True,
        help_text="When this sequence was last incremented"
    )

    class Meta:
        db_table = 'formatted_autofield_sequence'
        verbose_name = 'Formatted AutoField Sequence'
        verbose_name_plural = 'Formatted AutoField Sequences'
        indexes = [
            models.Index(fields=['key'], name='idx_sequence_key'),
        ]

    def __str__(self):
        return f"{self.key} (last_value={self.last_value})"

    def __repr__(self):
        return f"<Sequence: {self.key} last_value={self.last_value}>"

    def get_next_value(self):
        """
        Increment and return the next value in this sequence.

        IMPORTANT: This method MUST be called within a transaction.atomic() block
        and AFTER the sequence record has been locked with select_for_update().

        Returns:
            int: The next value in the sequence

        Example:
            with transaction.atomic():
                sequence = Sequence.objects.select_for_update().get(key='myapp.mymodel.myfield')
                next_val = sequence.get_next_value()
        """
        self.last_value += 1
        self.save(update_fields=['last_value', 'updated_at'])
        return self.last_value
