from django.db import models
from . import SideStoreModel, Tournament, FederalMatchCategory
import uuid

class Round(SideStoreModel):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
    tournament = models.ForeignKey(Tournament, on_delete=models.SET_NULL, related_name='rounds', null=True)
    index = models.IntegerField(default=0)
    parent = models.ForeignKey('self', blank=True, null=True, on_delete=models.SET_NULL, related_name='children')
    format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True)
    start_date = models.DateTimeField(null=True, blank=True)
    group_stage_loser_bracket = models.BooleanField(default=False)
    loser_bracket_mode = models.IntegerField(default=0)

    def delete_dependencies(self):
        for round in self.children.all():
            round.delete_dependencies()
            round.delete()
        for match in self.matches.all():
            match.delete_dependencies()
            match.delete()

    def __str__(self):
        if self.parent:
            return f"LB: {self.name()}"
        else:
            return self.name()

    def save(self, *args, **kwargs):
        self.store_id = str(self.get_tournament_id())
        super().save(*args, **kwargs)

    def get_tournament_id(self):
        if self.tournament:
            return self.tournament.id
        else:
            return None

    def name(self):
        if self.parent and self.parent.parent is None:
            return f"Classement {self.parent.name()}"
        elif self.parent and self.parent.parent is not None:
            return f"{self.parent.name()}"
        elif self.group_stage_loser_bracket is True:
            return "Classement de poule"
        else:
            if self.index == 0:
                return "Finale"
            elif self.index == 1:
                return "Demis"
            elif self.index == 2:
                return "Quarts"
            else:
                squared = 2 ** self.index
                return f"{squared}ème"

    def ranking_matches(self, hide_empty_matches):
        matches = []
        for child in self.children.all():

            child_matches = child.matches.all()
            if hide_empty_matches:
                child_matches = [m for m in child_matches if m.should_appear()]
            else:
                child_matches = [m for m in child_matches if m.disabled is False]

            matches.extend(child_matches)
            matches.extend(child.ranking_matches(hide_empty_matches))
        return matches

    def all_matches(self, hide_empty_matches):
        matches = []
        matches.extend(self.get_matches_recursive(hide_empty_matches))
        return matches

    def get_matches_recursive(self, hide_empty_matches):
        matches = list(self.matches.all())  # Retrieve matches associated with the current round
        if hide_empty_matches:
            matches = [m for m in matches if m.should_appear()]
        else:
            matches = [m for m in matches if m.disabled is False]

        matches.sort(key=lambda m: m.index)

        # Recursively fetch matches from child rounds
        for child_round in self.children.all():
            matches.extend(child_round.get_matches_recursive(hide_empty_matches))

        return matches

    def get_depth(self):
        depth = 0
        current_round = self
        while current_round.parent:
            depth += 1
            current_round = current_round.parent
        return depth

    def root_round(self):
        if self.parent is None:
            return self
        else:
            return self.parent.root_round()

    def all_matches_are_over(self):
        for match in self.matches.all():
            if match.end_date is None and match.disabled is False:
                return False

        return True

    def prepare_match_group(self, next_round, parent_round, loser_final, double_butterfly_mode, secondHalf):
        matches = self.matches.filter(disabled=False).order_by('index')
        if len(matches) == 0:
            return None
        if next_round:
            next_round_matches = next_round.matches.filter(disabled=False).order_by('index')
        else:
            next_round_matches = []

        if len(matches) < len(next_round_matches):
            all_matches = self.matches.order_by('index')
            filtered_matches = []

            # Process matches in pairs
            i = 0
            while i < len(all_matches):
                # Get the current match and its pair (if available)
                current_match = all_matches[i]
                pair_match = all_matches[i+1] if i+1 < len(all_matches) else None

                # Only filter out the pair if both matches are disabled
                if current_match.disabled and pair_match and pair_match.disabled:
                    # Skip one of the matches in the pair
                    if next_round_matches.filter(index=current_match.index // 2).exists():
                        filtered_matches.append(current_match)
                        filtered_matches.append(pair_match)
                    pass
                else:
                    # Keep the current match
                    if current_match.disabled == False:
                        filtered_matches.append(current_match)
                    # If there's a pair match, keep it too
                    if pair_match and pair_match.disabled == False:
                        filtered_matches.append(pair_match)

                # Move to the next pair
                i += 2

            # Replace the matches list with our filtered list
            matches = filtered_matches

        if matches:
            if len(matches) > 1 and double_butterfly_mode:
                midpoint = int(len(matches) / 2)
                first_half_matches = matches[:midpoint]
                if secondHalf:
                    first_half_matches = matches[midpoint:]
            else:
                first_half_matches = list(matches)  # Convert QuerySet to a list
                if self.index == 0 and loser_final:
                    loser_match = loser_final.matches.first()
                    if loser_match:
                        first_half_matches.append(loser_match)


            if first_half_matches:
                name = self.name()
                if parent_round and first_half_matches[0].name is not None:
                    name = first_half_matches[0].name
                match_group = self.tournament.create_match_group(
                    name=name,
                    matches=first_half_matches,
                    round_id=self.id
                )
                return match_group

        return None
