from django.db import models
from django.utils import timezone

from . import TournamentSubModel, Tournament, GroupStage, Match, CustomUser
from .enums import RegistrationStatus
from .player_enums import PlayerPaymentType
from ..services.email_service import TournamentEmailService, TeamEmailType
from ..utils.extensions import format_seconds
from ..services.currency_service import CurrencyService

import uuid

class TeamRegistration(TournamentSubModel):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
    tournament = models.ForeignKey(Tournament, on_delete=models.SET_NULL, related_name='team_registrations', null=True)
    group_stage = models.ForeignKey(GroupStage, null=True, blank=True, on_delete=models.SET_NULL, related_name='team_registrations')
    user = models.ForeignKey(CustomUser, null=True, blank=True, on_delete=models.SET_NULL, related_name='team_registrations')
    registration_date = models.DateTimeField(null=True, blank=True)
    call_date = models.DateTimeField(null=True, blank=True)
    bracket_position = models.IntegerField(null=True, blank=True)
    group_stage_position = models.IntegerField(null=True, blank=True)
    comment = models.CharField(max_length=200, null=True, blank=True)
    source = models.CharField(max_length=20, null=True, blank=True)
    source_value = models.CharField(max_length=200, null=True, blank=True)
    logo = models.CharField(max_length=200, null=True, blank=True) #models.FilePathField(path=os.path.join(settings.STATIC_ROOT, "images"), null=True, blank=True)
    name = models.CharField(max_length=200, null=True, blank=True)

    walk_out = models.BooleanField(default=False)
    wild_card_bracket = models.BooleanField(default=False)
    wild_card_group_stage = models.BooleanField(default=False)
    weight = models.IntegerField(default=0)
    locked_weight = models.IntegerField(null=True, blank=True)

    confirmation_date = models.DateTimeField(null=True, blank=True)
    qualified = models.BooleanField(default=False)

    final_ranking = models.IntegerField(null=True, blank=True)
    points_earned = models.IntegerField(null=True, blank=True)
    unique_random_index = models.IntegerField(default=0)

    def delete_dependencies(self):
        for player_registration in self.player_registrations.all():
            # player_registration.delete_dependencies()
            player_registration.delete()
        for team_score in self.team_scores.all():
            # match.delete_dependencies()
            team_score.delete()

    def __str__(self):
        if self.name:
            return self.name
            # return f"{self.name}: {self.player_names()}"
        return self.player_names()

    def get_tournament(self): # mandatory method for TournamentSubModel
        return self.tournament

    def player_names_as_list(self):
        players = list(self.players_sorted_by_rank)
        if len(players) == 0:
            return []
        elif len(players) == 1:
            return [players[0].name()]
        else:
            return [pr.name() for pr in players]

    def team_names(self):
        if self.name:
            return [self.name] #add an empty line if it's a team name
        else:
            return self.player_names_as_list()

    def shortened_team_names(self, forced=False):
        if self.name:
            return [self.name] #add an empty line if it's a team name
        else:
            player_count = self.player_registrations.count()
            if player_count == 0:
                if self.wild_card_bracket:
                    return ['Place réservée wildcard']
                elif self.wild_card_group_stage:
                    return ['Place réservée wildcard']
                else:
                    return ['Place réservée']
            elif player_count == 1:
                players = self.players_sorted_by_rank
                return [players[0].shortened_name(forced=forced)]
            else:
                players = self.players_sorted_by_rank
                return [pr.shortened_name(forced=forced) for pr in players]

    @property
    def players_sorted_by_rank(self):
        return self.player_registrations.all().order_by('rank')

    @property
    def players_sorted_by_captain(self):
        return self.player_registrations.all().order_by('-captain')

    def player_names(self):
        names = self.player_names_as_list()
        str = " - ".join(names)
        if len(str) > 0:
            return str
        else:
            return "no players"

    def formatted_team_names(self):
        if self.name:
            return self.name
        names = [pr.last_name for pr in self.players_sorted_by_rank][:2]  # Take max first 2
        joined_names = " / ".join(names)
        if joined_names:
            return f"Paire {joined_names}"
        return "Détail de l'équipe"

    def next_match(self):
        all_matches = [ts.match for ts in self.team_scores.all() if ts.match is not None]
        now = timezone.now()
        all_matches = sorted(all_matches, key=lambda m: m.start_date if m.start_date is not None else now)
        matches = [m for m in all_matches if m.end_date is None]
        if matches:
            return matches[0]
        else:
            return None

    def next_stage(self):
        matches = map(lambda ts: ts.match, self.team_scores.all())
        matches = [m for m in matches if m.group_stage is None]
        matches = sorted(matches, key=lambda m: m.round.index)

        # matches = self.teamscore_set
        # matches = Match.objects.filter(group_stage__isnull=True, team_scores__player_registrations__id=self.id).order_by('round__index')
        # print(f"matches = {len(matches)}")
        if matches:
            return matches[0].round.name()
        elif self.group_stage:
            return self.group_stage.name()
        else:
            return "--"

    def is_valid_for_summon(self):
        return self.players_sorted_by_rank.count() > 0 or self.name is not None

    def initial_weight(self):
        if self.locked_weight is None:
            return self.weight
        else:
            return self.locked_weight

    def local_call_date(self):
        timezone = self.tournament.timezone()
        if self.call_date:
            return self.call_date.astimezone(timezone)
        else:
            # print("no date")
            return None

    def local_registration_date(self):
        timezone = self.tournament.timezone()
        if self.registration_date:
            return self.registration_date.astimezone(timezone)
        else:
            # print("no date")
            return None

    def out_of_tournament(self):
        return self.walk_out

    def get_other_player(self, player):
        for p in self.players_sorted_by_rank:
            if p != player:
                return p
        return None

    def is_in_waiting_list(self):
        return self.tournament.get_team_waiting_list_position(self)

    def get_matches(self):
        matches = Match.objects.filter(team_scores__team_registration=self).distinct()
        # print(f"All matches for team {self.id}: {matches.count()}")
        # for match in matches:
        #     print(f"Match {match.id}: start_date={match.start_date}, end_date={match.end_date}")
        return matches

    def get_upcoming_matches(self):
        if self.tournament and self.tournament.display_matches() is False:
            return []

        matches = self.get_matches()
        upcoming = matches.filter(end_date__isnull=True).order_by('start_date')
        # print(f"Upcoming matches count: {upcoming.count()}")
        return [match.live_match() for match in upcoming]

    def get_completed_matches(self):
        matches = self.get_matches()
        completed = matches.filter(end_date__isnull=False).order_by('-end_date')
        # print(f"Completed matches count: {completed.count()}")
        return [match.live_match() for match in completed]

    def get_statistics(self):

        stats = {
            'final_ranking': self.get_final_ranking(),
            'weight': self.weight,
            'points_earned': self.get_points_earned(),
            'initial_stage': self.get_initial_stage(),
            'matches_played': self.count_matches_played(),
            'victory_ratio': self.calculate_victory_ratio(),
            'time_played': self.calculate_time_played(),
            'team_rank': self.team_rank_label(),
            'total_teams': self.total_teams(),
        }
        return stats

    def team_rank(self):
        teams = self.tournament.teams(False)  # Get list of TeamItem objects
        try:
            # Find the TeamItem that corresponds to this TeamRegistration
            team_index = next(i for i, team in enumerate(teams)
                            if team.team_registration.id == self.id)
            return team_index + 1
        except (StopIteration, ValueError):
            return None

    def team_rank_label(self):
        team_rank = self.team_rank()
        if team_rank is None:
            return "--"
        return f"{team_rank}"

    def total_teams(self):
        teams = self.tournament.teams(False)
        return f"{len(teams)}"

    def get_initial_stage(self):
        matches = self.get_matches().order_by('start_date')
        first_match = matches.first()
        if first_match:
            if first_match.group_stage:
                return "Poule"
            elif first_match.round:
                return first_match.round.name()
        return None


    def get_final_ranking(self):
        get_final_ranking_component = self.get_final_ranking_component()
        if get_final_ranking_component:
            return get_final_ranking_component + self.ranking_delta()
        return None

    def get_final_ranking_component(self):
        if self.final_ranking:
            if self.final_ranking == 1:
                return "1er"
            return f"{self.final_ranking}ème"
        return None

    def ranking_delta(self):
        team_rank = self.team_rank()
        if team_rank is None or self.final_ranking is None:
            return ""

        sign = "-"
        if team_rank > self.final_ranking:
            sign = "+"
        if team_rank == self.final_ranking:
            sign = "+"
        return f" ({sign}"+f"{abs(self.final_ranking - team_rank)})"

    def get_points_earned(self):
        return self.points_earned

    def calculate_total_duration(self):
        total_seconds = 0
        for match in self.get_matches().filter(end_date__isnull=False):
            if match.start_date and match.end_date:
                duration = (match.end_date - match.start_date).total_seconds()
                total_seconds += duration

        if total_seconds > 0:
            hours = int(total_seconds // 3600)
            minutes = int((total_seconds % 3600) // 60)
            if hours > 0:
                return f"{hours}h{minutes:02d}"
            return f"{minutes}min"
        return None

    def count_matches_played(self):
        return self.get_matches().filter(end_date__isnull=False).count()

    def calculate_time_played(self):
        total_seconds = 0
        for match in self.get_matches().filter(end_date__isnull=False):
            total_seconds += match.smart_time_played()

        return format_seconds(total_seconds)

    def calculate_victory_ratio(self):
        matches = self.get_matches().filter(end_date__isnull=False)
        total_matches = matches.count()
        if total_matches > 0:
            wins = matches.filter(winning_team_id=self.id).count()
            # ratio = (wins / total_matches) * 100
            return f"{wins}/{total_matches}"
        return None

    def has_registered_online(self):
        for p in self.players_sorted_by_rank:
            if p.registered_online:
                return True
        return False

    def formatted_special_status(self):
        if self.wild_card_bracket:
            return "(wildcard tableau)"
        if self.wild_card_group_stage:
            return "(wildcard poule)"
        return ""

    def set_time_to_confirm(self, ttc):
        for p in self.players_sorted_by_rank:
            if p.registered_online:
                p.time_to_confirm = ttc
                p.registration_status = RegistrationStatus.PENDING
                p.save()

    def cancel_time_to_confirm(self):
        for p in self.players_sorted_by_rank:
            if p.registered_online:
                save = False
                if p.time_to_confirm is not None:
                    save = True
                    p.time_to_confirm = None
                if p.registration_status == RegistrationStatus.PENDING:
                    save = True
                    p.registration_status = RegistrationStatus.WAITING
                if save:
                    p.save()

    def needs_confirmation(self):
        """Check if this team needs to confirm their registration"""
        # Check if any player has status PENDING and is registered online
        return any(p.registration_status == RegistrationStatus.PENDING and p.registered_online
                for p in self.players_sorted_by_rank)

    def get_confirmation_deadline(self):
        """Get the confirmation deadline for this team"""
        deadlines = [p.time_to_confirm for p in self.players_sorted_by_rank if p.time_to_confirm is not None]
        return max(deadlines) if deadlines else None

    def confirm_pre_registration(self):
        """Confirm the team's pre-registration"""
        # Update all players in the team
        for player in self.players_sorted_by_rank:
            print(f"Updating player {player.first_name} {player.last_name} (ID: {player.id})")
            player.registration_status = RegistrationStatus.PENDING
            player.save()

    def confirm_registration(self, payment_intent_id=None):
        """Confirm the team's registration after being moved from waiting list"""
        print(f"Confirming registration for team {self.id} with payment {payment_intent_id}")

        # Update all players in the team
        for player in self.players_sorted_by_rank:
            print(f"Updating player {player.first_name} {player.last_name} (ID: {player.id})")
            # # Vérifier si ce joueur a déjà ce payment_id
            # if player.payment_id == payment_intent_id and payment_intent_id:
            #     print(f"Player {player.id} already has payment_id {payment_intent_id}, skipping")
            #     continue
            player.time_to_confirm = None
            player.payment_id = payment_intent_id
            if payment_intent_id is not None:
                player.payment_type = PlayerPaymentType.CREDIT_CARD
            player.registration_status = RegistrationStatus.CONFIRMED
            player.save()
            print(f"✅ Updated player {player.id} with payment {payment_intent_id}")

    def confirm_if_placed(self):
        if self.needs_confirmation() is False:
            return
        if self.group_stage or self.bracket_position or self.confirmation_date is not None:
            for player in self.players_sorted_by_rank:
                if player.registration_status is not RegistrationStatus.CONFIRMED:
                    player.time_to_confirm = None
                    player.registration_status = RegistrationStatus.CONFIRMED
                    player.save()

    # Add to TeamRegistration class in team_registration.py
    def get_payment_status(self):
        """
        Gets the payment status for this team.
        Returns:
        - 'PAID': If all players in the team have paid
        - 'UNPAID': If no player has paid
        - 'MIXED': If some players have paid and others haven't (unusual case)
        """
        # Get all player registrations for this team
        player_registrations = self.players_sorted_by_rank

        # If we have no players, return None
        if not player_registrations.exists():
            return None

        # Check payment status for each player
        payment_statuses = [player.has_paid() for player in player_registrations]

        print(f"Payment statuses: {payment_statuses}")
        # If all players have paid
        if all(payment_statuses):
            return 'PAID'

        # If no players have paid
        if not any(payment_statuses):
            return 'UNPAID'

        # If some players have paid and others haven't (unusual case)
        return 'MIXED'

    def is_payment_required(self):
        """Check if payment is required for this team"""
        return self.tournament.should_request_payment() and self.is_in_waiting_list() < 0

    def is_paid(self):
        """Check if this team has paid"""
        status = self.get_payment_status()
        return status == 'PAID'

    def get_remaining_fee(self):
        # Get all player registrations for this team
        player_registrations = self.players_sorted_by_rank
        # Check payment status for each player
        payment_statuses = [player.get_remaining_fee() for player in player_registrations]
        return sum(payment_statuses)

    def get_remaining_fee_formatted(self):
        """Get the remaining fee formatted with the tournament's currency."""
        remaining_fee = self.get_remaining_fee()
        tournament = self.get_tournament()
        currency_code = tournament.currency_code if tournament and tournament.currency_code else 'EUR'
        return CurrencyService.format_amount(remaining_fee, currency_code)

    def is_confirmation_expired(self):
        """
        Check if the confirmation deadline has expired.
        Returns:
            bool: True if expired, False if still valid or no deadline exists
        """
        deadline = self.get_confirmation_deadline()
        if not deadline:
            return False
        current_time = timezone.now()

        return deadline < current_time

    def format_confirmation_deadline(self):
        """
        Format the confirmation deadline in a human-readable format.
        Returns:
            str: Formatted deadline, or None if no deadline exists
        """
        deadline = self.get_confirmation_deadline()
        if not deadline:
            return None

        if self.tournament and self.tournament.timezone():
            deadline = deadline.astimezone(self.tournament.timezone())

        return deadline.strftime("%d/%m/%Y à %H:%M")

    def check_confirmation_deadline(self, tournament_context=None):
        """
        Check if the confirmation deadline for this team has expired and perform necessary actions.

        Args:
            tournament_context (dict, optional): Pre-calculated tournament context to avoid redundant calls.
                                                If None, will calculate on-demand.

        """
        now = timezone.now()
        tournament = self.tournament

        if not tournament:
            return

        # Use provided context or calculate if not provided
        if tournament_context is None:
            teams = tournament.teams(True)
            waiting_list_teams = tournament.waiting_list_teams(teams)
            ttc = tournament.calculate_time_to_confirm(len(waiting_list_teams)) if waiting_list_teams is not None else None
            first_waiting_list_team = tournament.first_waiting_list_team(teams)
            is_online_registration_irrevelant = tournament.is_online_registration_irrevelant()
        else:
            ttc = tournament_context.get('ttc')
            first_waiting_list_team = tournament_context.get('first_waiting_list_team')
            is_online_registration_irrevelant = tournament_context.get('is_online_registration_irrevelant', False)

        # Get all players in this team
        team_players = self.player_registrations.filter(registered_online=True)

        should_update_team = False
        should_send_mail = False

        for team_player in team_players:
            if is_online_registration_irrevelant:
                team_player.registration_status = RegistrationStatus.CANCELED
                team_player.save()
            elif team_player.time_to_confirm is None and first_waiting_list_team is not None:
                self.set_time_to_confirm(ttc)
                should_send_mail = True
                print(team_player, "team_player.time_to_confirm is None and", ttc)
            elif team_player.time_to_confirm is not None and now > team_player.time_to_confirm:
                if first_waiting_list_team is not None:
                    team_player.registration_status = RegistrationStatus.CANCELED
                    self.registration_date = now
                    should_update_team = True

                team_player.time_to_confirm = None
                team_player.save()
                print(team_player, "time_to_confirm = ", team_player.time_to_confirm)

        if should_update_team:
            self.save()
            print(f"Team {self} confirmation expired in tournament {tournament.id}")


        if should_send_mail:
            TournamentEmailService.notify_team(
                self,
                tournament,
                TeamEmailType.REQUIRES_TIME_CONFIRMATION
            )

    def is_unregistration_possible(self):
        if self.call_date is not None:
            return False
        if self.bracket_position is not None:
            return False
        if self.group_stage_position is not None:
            return False
        return True

    def is_positioned(self):
        return self.bracket_position is not None or self.group_stage_position is not None

    def get_team_registration_fee(self):
        # Get all player registrations for this team
        player_registrations = self.players_sorted_by_rank
        # Check payment status for each player
        payment_statuses = [player.get_player_registration_fee() for player in player_registrations]
        return sum(payment_statuses)
