"""Models for the mainapp."""

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


class Venue(models.Model):
    """Represents a Venue and Waters."""

    VENUE_TYPES = (
        ("FISHERY", "Fishery"),
        ("CLUB", "Club"),
        ("PRIVATE", "Private")
    )

    name = models.CharField(max_length=255)
    description = models.TextField(blank=True)
    extra_notes = models.TextField(blank=True)
    venue_type = models.CharField(choices=VENUE_TYPES, max_length=50)

    # Contact information
    phone_number = models.CharField(max_length=100)
    email_address = models.EmailField()
    website_url = models.URLField()

    # Location information
    street_address = models.CharField(max_length=100)
    city = models.CharField(max_length=255)
    provence = models.CharField(max_length=100)
    postal_code = models.CharField(max_length=20)
    country = models.CharField(max_length=100)
    latitude = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True)
    longitude = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True)

    # Socials information
    twitter_url = models.URLField(blank=True)
    instagram_url = models.URLField(blank=True)
    facebook_url = models.URLField(blank=True)

    def __str__(self):
        return self.name


class Waters(models.Model):
    """Represents the waters of a Venue"""

    WATER_TYPES = (
        ("CW", "Commercial Water"),
        ("NSW", "Natural Still Water"),
        ("C", "Canal"),
        ("R", "River"),
        ("L", "Loch"),
    )

    FISH_TYPES = (
        ("C", "Coarse"),
        ("SC", "Specimen Carp"),
        ("G", "Game"),
        ("P", "Predator"),
    )

    venue = models.ForeignKey(Venue, on_delete=models.CASCADE)

    name = models.CharField(max_length=100)
    description = models.TextField(max_length=255)

    pegs_min = models.IntegerField()
    pegs_max = models.IntegerField()
    water_type = models.CharField(choices=WATER_TYPES, max_length=50)
    fish_type = models.CharField(choices=FISH_TYPES, max_length=50)

    # water_map = models.ImageField()

    def __str__(self):
        return self.name


# 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 SectionValidator:
#     """Validation class for the `section` field on the `member` model."""

#     def __init__(self, max_value="ZZZ"):
#         self.max_value = max_value.upper()
#         self.alphabet_size = ord("Z") - ord("A") + 1

#     def is_valid(self, section: str, team_sections: list[str]=None) -> bool:
#         """Returns boolean if the section passed is valid."""
#         section = section.upper()

#         if not self._is_alphanumeric(section):
#             return False

#         if not self._is_in_alphabet(section[0]):
#             return False

#         if not self._is_in_range(section):
#             return False

#         if team_sections:
#             if not self._is_unique(section, team_sections):
#                 return False

#             if not self._is_not_adjacent(section, team_sections):
#                 return False

#         return True

#     def _is_alphanumeric(self, section: str) -> bool:
#         """Returns boolean if all characters in the passed string are alphanumerical."""
#         return all(c.isalnum() for c in section)

#     def _is_in_alphabet(self, c) -> bool:
#         """Returns boolean if the passed character is alphabetical."""
#         return "A" <= c <= "Z"

#     def _is_in_range(self, section) -> bool:
#         """Returns boolean if the passed section less or equal to the max value."""
#         section_value = self._section_value(section)
#         max_value = self._section_value(self.max_value)

#         return section_value <= max_value

#     def _is_unique(self, section, team_sections) -> bool:
#         """Returns boolean if the passed section is unique amongst `team_sections`."""
#         return section not in team_sections

#     def _is_not_adjacent(self, section, team_sections) -> bool:
#         """Returns boolean if the passed section is not adjacent to any `team_sections`."""
#         for team_section in team_sections:
#             team_section_value = self._section_value(team_section)
#             section_value = self._section_value(section)
#             if abs(team_section_value - section_value) <= 1:
#                 return False

#         return True

#     def _section_value(self, section):
#         """Returns the value of the passed section."""
#         n = len(section)
#         value = sum((ord(c) - ord("A") + 1) * self.alphabet_size ** (n - i - 1) for i, c in enumerate(section))
#         return value


# class SectionManager(models.Manager):

#     @staticmethod
#     def get_max_section():
#         max_section = None
#         max_number = -1

#         # Iterate through all sections in the database
#         for section in Section.objects.all():
#             section_name = section.name
#             section_number = 0

#             # Calculate the section number based on the section name
#             for i, char in enumerate(section_name):
#                 section_number += (ord(char) - ord('A') + 1) * (26 ** (len(section_name) - i - 1))

#             # Check if this section has a higher number than the current maximum
#             if section_number > max_number:
#                 max_number = section_number
#                 max_section = section_name

#         return max_section

#     @staticmethod
#     def find_next_section(current_section):
#         if not current_section:
#             return 'A'

#         # Split current section name into a list of characters
#         chars = list(current_section)

#         # Increment the last character
#         chars[-1] = chr(ord(chars[-1]) + 1)

#         # Check if the last character is "Z", and carry over to the next character if necessary
#         for i in range(len(chars) - 1, -1, -1):
#             if chars[i] > 'Z':
#                 chars[i] = 'A'
#                 if i == 0:
#                     # If the first character needs to be incremented, add a new character "A"
#                     chars.insert(0, 'A')
#                 else:
#                     # Increment the previous character
#                     chars[i - 1] = chr(ord(chars[i - 1]) + 1)
#             else:
#                 break

#         # Join the characters back into a string and return the result
#         return ''.join(chars)

# class Section(models.Model):
#     """Represents a fishing area. Members can be assigned to a section,
#     but no 2 teammates can be in the same or adjacent section."""

#     character = models.CharField(max_length=3, unique=True, null=False)

#     objects = SectionManager()

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

#     def __str__(self) -> str:
#         return self.character


# 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, related_name='members')
#     peg_number = models.PositiveIntegerField(null=True, editable=True, unique=True)
#     section = models.ForeignKey(to=Section, on_delete=models.SET_NULL, null=True, swappable=True, related_name='members')

#     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.number}) [section {self.section.character}]"

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


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

#     number = models.PositiveIntegerField(unique=True, null=False, blank=False)

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