from string import ascii_uppercase

from django.db import models
from django.core.exceptions import ValidationError

from django.db import models


class ReusableAutoField(models.PositiveIntegerField):
    """A django auto field that can reuse deleted primary keys"""

    def get_next_available_id(self, model_cls, using=None):
        """
        Returns the next available id for the given model class.
        """
        all_ids = set(range(1, model_cls._default_manager.count()+1))
        used_ids = set(model_cls._default_manager.all().values_list('pk', flat=True))
        available_ids = all_ids - used_ids

        if available_ids:
            return min(available_ids)

        if used_ids:
            return max(used_ids) + 1

        return 1

    def get_default(self):
        """Returns the default value for this field"""

        return self.get_next_available_id(self.model)


class Peg(models.Model):
    """Represents a person's peg"""

    peg_number = ReusableAutoField(primary_key=True, default=ReusableAutoField.get_default, editable=False)

    def __str__(self):
        return f"Peg {self.peg_number}"


def validate_team_size(value):
    if Member.objects.filter(team=value).count() >= 3:
        raise ValidationError('Team already has maximal amount of members (3)')


class Member(models.Model):
    """Represents a member of a team"""

    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)
    team = models.ForeignKey("Team", on_delete=models.SET_NULL, null=True, blank=True, validators=(validate_team_size,), related_name='members')
    peg_number = models.PositiveIntegerField(null=True, editable=True, unique=True)
    # peg = models.OneToOneField("Peg", on_delete=models.SET_NULL, null=True, blank=True)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # If the peg_number field is not set, we assign it the smallest
        # available positive integer, excluding any used values.
        if not self.peg_number:
            used_peg_numbers = Member.objects.exclude(id=self.id).exclude(peg_number=None).values_list("peg_number", flat=True)
            peg_numbers = set(range(1, Member.objects.count() + 1)) - set(used_peg_numbers)
            if peg_numbers:
                self.peg_number = min (peg_numbers)

    def __str__(self):
        return f"{self.first_name} {self.last_name} (team {self.team.team_number}))"

    @property
    def fullname(self) -> str:
        return f"{self.first_name} {self.last_name}"


BLOCKED_SECTION_LETTERS = ["i"]  # lowercase only, sections cannot be any of these letters#


class Team(models.Model):
    """Represents a team"""

    team_number = ReusableAutoField(primary_key=True, default=ReusableAutoField.get_default, editable=False)
    section_letter = models.CharField(max_length=1, unique=True, choices=[
        (char, char) for char in ascii_uppercase if char.lower() not in BLOCKED_SECTION_LETTERS
    ])

    def __str__(self):
        return f"Team {self.team_number}"

    @property
    def members(self) -> list[Member]:
        Member.objects.filter(team=self)


def validate_section_character(value):
    """Validates the section character"""

    value = value.upper()
    banned_characters = ["I"]

    if value in banned_characters:
        raise ValidationError(f"The character <{value}> is a prohibited character.")


# class Section(models.Model):
#     """Represents a section of the scoreboard"""

#     # character field stores a single character but doesnt allow for 'I' or 'i'
#     character = models.CharField(primary_key=True, max_length=1, validators=(validate_section_character, ))

#     def clean(self):
#         self.character = self.character.upper()

#     def __str__(self):
#         return f"Section {self.character}"


#class Scoreboard(models.Model):
#    class Status(models.IntegerChoices):
#        ACTIVE = 1, "Active"
#        INACTIVE = 2, "Inactive"
#        ARCHIVED = 3, "Archived"
#
#    name = models.CharField(max_length=255)
#    category = models.CharField(max_length=255)
#    price = models.DecimalField(max_digits=10, decimal_places=2)
#    cost = models.DecimalField(max_digits=10, decimal_places=2)
#    status = models.PositiveSmallIntegerField(choices=Status.choices)
#
#    def __str__(self):
#        return self.name