class TournamentView:
    def __init__(self):
        """
        Create the main tournament menu
        """
        cls()
        icon()
        self.list_all_tournament_name = search_all_tournament()
        self.list_tournaments = []
        for self.tournament_name in self.list_all_tournament_name:
            self.tournament = Tournament()
            self.tournament.read_in_db(self.tournament_name)
            self.list_tournaments.append(self.tournament)
        print("Menu des stats Tournoi \n\n"
              "1. Voir la liste de tous les Tournois\n"
              "2. Voir les tours d'un Tournoi avec son nom\n"
              "3. Voir les matchs d'un Tournoi avec son nom\n"
              "4. Voir les Joueurs d'un Tournoi avec son nom\n"
              "5. Retour")
        self.choice_menu = 0
        while not 5 >= int(self.choice_menu) >= 1:
            self.choice_menu = input(
                "Faites votre choix en tapant le numéro de menu (ex. 1, 2, 3, 4, ne tapez qu'un seul choix) : "
            )
            if not self.choice_menu.isdigit():
                self.choice_menu = 0
        if int(self.choice_menu) == 1:
            self.show_list_all_tournament()
            input()
        elif int(self.choice_menu) == 2:
            if self.show_one_tournament():
                self.show_tour()
                input()
            else:
                print("Ce tournoi n'existe pas")
                input()
        elif int(self.choice_menu) == 3:
            if self.show_one_tournament():
                self.show_match()
                input()
            else:
                print("Ce tournoi n'existe pas")
                input()
        elif int(self.choice_menu) == 4:
            if self.show_one_tournament():
                self.show_player()
                input()
            else:
                print("Ce tournoi n'existe pas")
                input()
        elif int(self.choice_menu) == 5:
            pass

    def show_list_all_tournament(self):
        """
        Displays a table of all the tournaments in the DB
        """
        cls()
        icon()
        print("Liste de tous les Tournois\n".center(width_calculated()))
        print(("=" * 113).center(width_calculated()))
        print(f'| {"Nom du Tournoi".center(35)} |'
              f'{"Ville".center(35)} |'
              f'{"Date".center(35)} |'.center(width_calculated()))
        for self.tournament in self.list_tournaments:
            print(("-" * 113).center(width_calculated()))
            print(f'| {self.tournament.name.center(35)} |'
                  f'{self.tournament.location.center(35)} |'
                  f'{self.tournament.date.center(35)} |'.center(
                      width_calculated()))
        print(("-" * 113).center(width_calculated()))

    def show_one_tournament(self):
        """
        Search if a tournament exists by entering its name
        :return: True if the torunoi exists, False if it does not exist
        """
        self.show_list_all_tournament()
        self.choice_tournament_name = input(
            "Taper le nom du Tournoi : ").capitalize()
        cls()
        icon()
        for self.tournament in self.list_tournaments:
            if self.choice_tournament_name == self.tournament.name:
                self.tournament_choice = self.tournament
                print("Stat du Tournoi Tournois\n".center(width_calculated()))
                print(("=" * 113).center(width_calculated()))
                print(f'| {"Nom du Tournoi".center(35)} |'
                      f'{"Ville".center(35)} |'
                      f'{"Date".center(35)} |'.center(width_calculated()))
                print(("-" * 113).center(width_calculated()))
                print(f'| {self.tournament.name.center(35)} |'
                      f'{self.tournament.location.center(35)} |'
                      f'{self.tournament.date.center(35)} |'.center(
                          width_calculated()))
                print(("-" * 113).center(width_calculated()))
                print("\n")
                return True
            else:
                return False

    def show_tour(self):
        """
        Displays a table of rounds in the selected tournament
        """
        print("Stat des Tours du Tournoi\n".center(width_calculated()))
        print(("=" * 113).center(width_calculated()))
        print(f'| {"Tour".center(54)} |'
              f'{"Date".center(53)} |'.center(width_calculated()))
        self.counter = 0
        for self.round_dict in self.tournament_choice.list_rounds_played:
            for self.round, self.date in self.round_dict.items():
                self.counter += 1
                print(("-" * 113).center(width_calculated()))
                print(f'| {("Tour " + str(self.counter)).center(53)} |'
                      f' {self.date.center(53)} |'.center(width_calculated()))
        print(("-" * 113).center(width_calculated()))

    def show_player(self):
        """
        Displays a table of players in the selected tournament
        """
        self.sort_rank = input("1. Trier les Joueurs par Nom\n"
                               "2. Trier les Joueurs par Rang\n")
        if self.sort_rank == "1":
            self.sort_rank = None
        elif self.sort_rank == "2":
            self.sort_rank = True
        print("Liste des Joueurs\n".center(width_calculated()))
        print(("=" * 113).center(width_calculated()))
        print(f'| {"Nom du Joueur".center(35)} |'
              f'{"Prénom du Joueur".center(35)} |'
              f'{"Rang".center(35)} |'.center(width_calculated()))
        self.list_players = self.tournament_choice.list_players
        if self.sort_rank:
            self.list_players = sorted(self.list_players,
                                       key=lambda player: player.rank,
                                       reverse=True)
        else:
            self.list_players = sorted(self.list_players,
                                       key=lambda player: player.name)
        for self.player in self.list_players:
            print(("-" * 113).center(width_calculated()))
            print(f'| {self.player.name.center(35)} |'
                  f'{self.player.first_name.center(35)} |'
                  f'{str(self.player.rank).center(35)} |'.center(
                      width_calculated()))
        print(("-" * 113).center(width_calculated()))

    def show_match(self):
        """
        Displays a table of matches in the selected tournament
        """
        print("Stat des Matchs du Tournois\n".center(width_calculated()))
        self.counter = 0
        for self.round_dict in self.tournament_choice.list_rounds_played:
            for self.round, self.date in self.round_dict.items():
                self.counter += 1
                print("\n")
                print(("-" * 113).center(width_calculated()))
                print(
                    f'| {("Tour " + str(self.counter) + "  " + self.date).center(110)} |'
                    .center(width_calculated()))
                print(f'| {"Joueur 1".center(53)} VS'
                      f'{"Joueur 2".center(54)} |'.center(width_calculated()))
                print(("-" * 113).center(width_calculated()))
                self.list_matchs = []
                for self.player_id in self.round.round:
                    for self.player in self.tournament_choice.list_players:
                        if int(self.player_id) == self.player.id:
                            self.list_matchs.append(
                                str(self.player.name + " " +
                                    self.player.first_name + " -- point : " +
                                    str(self.round.round[self.player_id])))
                while self.list_matchs:
                    print(f'| {self.list_matchs.pop(0).center(53)} VS'
                          f'{self.list_matchs.pop(0).center(54)} |'.center(
                              width_calculated()))
                    print(("-" * 113).center(width_calculated()))
class Game:
    def __init__(self):
        """
        Displays the main menu
        """
        cls()
        icon()
        print(f"{'=' * width_calculated()}\n")
        print(f'{"Menu Principal".center(width_calculated())}\n \n')
        print("1. Nouveau Tournoi\n"
              "2. Reprendre un Tournoi non terminé\n"
              "3. Afficher la liste des Tournois\n"
              "4. Afficher les stats des Joueurs\n"
              "5. Quitter le Jeux")

        self.choice_menu = 0
        while not 5 >= int(self.choice_menu) >= 1:
            self.choice_menu = input(
                "Faites votre choix en tapant le numéro de menu (ex. 1, 2, 3, 4, 5, ne tapez qu'un seul choix) : ")
            if not self.choice_menu.isdigit():
                self.choice_menu = 0

    @property
    def create_tournament(self):
        """
        requests the information for the creation of the tournament.
        The control is done with the Regex
        :return:List info tournament
        """
        cls()
        icon()
        self.tournament_name, self.tournament_location, self.tournament_time = str(), str(), "0"

        print(f'{"Nouveau Tournoi".center(width_calculated())}\n'
              f'Avant de commencer le Tournoi, il me faut quelques informations : \n'
              )

        while not re.match(r"^[A-Z\sa-z-]+$", self.tournament_name):
            self.tournament_name = input('Le nom du Tournoi (attention de ne pas '
                                         'renseigner un nom déjà existant) : ').capitalize()
        while not re.match(r"^[A-Z\sa-z-]+$", self.tournament_location):
            self.tournament_location = input('La ville du Tournoi : ').capitalize()
        while not re.match(r"^[1-3]?$", self.tournament_time):
            self.tournament_time = input('Choisissez le format de temps du Tournoi\n'
                                         '1. Bullet\n'
                                         '2. Coup rapide\n'
                                         '3. Blitz\n'
                                         'Choix : ')
        if self.tournament_time == "1":
            self.tournament_time = "Bullet"
        elif self.tournament_time == "2":
            self.tournament_time = "Coup rapide"
        elif self.tournament_time == "3":
            self.tournament_time = "Blitz"
        self.list_info_tournament = [self.tournament_name, self.tournament_location, self.tournament_time]
        return self.list_info_tournament

    @property
    def resume_tournament(self):
        """
        request the name of the tournament
        :return:name of tournmaent (string)
        """
        cls()
        icon()
        self.list_tournament_not_over = list()
        for self.tournament_name in search_all_tournament():
            self.tournament = Tournament()
            self.tournament.read_in_db(self.tournament_name)
            if not self.tournament.tournament_over:
                self.list_tournament_not_over.append(self.tournament)
        print('Vous souhaitez reprendre un Tournoi, si la liste est vide, '
              'taper Entrée pour revenir au menu principal\n')
        print(("=" * 113).center(width_calculated()))
        print(f'| {"Nom du Tournoi".center(35)} |'
              f'{"Ville".center(35)} |'
              f'{"Date".center(35)} |'.center(width_calculated())
              )
        for self.tournament in self.list_tournament_not_over:
            print(("-" * 113).center(width_calculated()))
            print(f'| {self.tournament.name.center(35)} |'
                  f'{self.tournament.location.center(35)} |'
                  f'{self.tournament.date.center(35)} |'.center(width_calculated())
                  )
        print(("-" * 113).center(width_calculated()))
        self.name_tournament = " "
        while not (self.name_tournament in search_all_tournament() or self.name_tournament == ""):
            self.name_tournament = input('Tapez le nom du Tournoi : ').capitalize()
        return self.name_tournament

    @staticmethod
    def not_pair():
        print("Il manque un  Joueur, Tournoi impossible avec un nombre de Joueur impair")

    def tournament_over(self):
        """
        display tournament over
        """
        self.over = print('Ce Tournoi est terminé !!!')
        input('Taper sur Entrée pour revenir au menu principal')

    def choice_player(self, list_player):
        """
        Menu of choices for creating or loading a player
        :param list_player: list instance player in tournament
        :return:choice ( R or N or C ) -- string
        """
        self.choice = input(
            'Taper "N" pour un Nouveau Joueur, '
            f'{"R pour rechercher un Joueur déjà existant, " if list_player != [] else ""}'
            '"C" pour commencer le Tournoi : ').upper()
        return self.choice

    @property
    def create_player(self):
        """
        Allows to fill the information of a player, the control of the name and first name is done with REGEX
        and the date of birth with DateTime
        :return: List of information for the model Player class (String)
        """
        cls()
        icon()
        print("Enregistrement d'un joueur pour ce Tournoi\n")
        self.name = str()
        while not re.match(r"^[A-Z\sa-z-]+$", self.name):
            self.name = input('Nom de Famille du Joueur : ')
        self.first_name = str()
        while not re.match(r"^[A-Z\sa-z-]+$", self.first_name):
            self.first_name = input('Prénom du Joueur : ')
        while True:
            try:
                self.date_born = input('Date de Naissance au format JJ/MM/AAAA (ex : 14/07/1990) : ')
                self.date_verif = datetime.datetime.strptime(self.date_born, "%d/%m/%Y")
                break
            except ValueError:
                pass
        self.day, self.month, self.year = map(int, self.date_born.split('/'))
        self.date_born = datetime.date(self.year, self.month, self.day)
        self.genre = str()
        while not re.match(r"^[H|F]$", self.genre):
            self.genre = input('Choisisser le genre Femme ou Homme en tapant F ou H : ')
        self.list_player_info = [self.name.capitalize(), self.first_name.capitalize(), self.date_born, self.genre]
        print(f'Le Nouveau Joueur est {self.name} {self.first_name} née le {self.date_born.strftime("%d/%m/%Y")}\n')
        return self.list_player_info

    @property
    def read_player(self):
        """
        Generates a table of players and allows to choose a day thanks to its TinyDB ID
        :return: ID choice
        """
        cls()
        icon()
        self.list_all_players = list()
        for self.player_id in search_all_player():
            self.player = Player()
            self.player.load_player(self.player_id)
            self.list_all_players.append(self.player)
        print('Rechercher un Joueur pour ce Tournoi\n')
        print(("=" * 177).center(width_calculated()))
        print(f'| {"ID du Joueur".center(25)} |'
              f'{"Nom du Joueur".center(35)} |'
              f'{"Prénom du Joueur".center(35)} |'
              f'{"Date de naissance du joueur".center(35)} |'
              f'{"Rang".center(35)} |'.center(width_calculated())
              )
        self.list_all_players = sorted(self.list_all_players, key=lambda player: player.name)
        for self.player in self.list_all_players:
            print(("-" * 177).center(width_calculated()))
            print(f'| {str(self.player.id).center(25)} |'
                  f'{self.player.name.center(35)} |'
                  f'{self.player.first_name.center(35)} |'
                  f'{self.player.date_born.center(35)} |'
                  f'{str(self.player.rank).center(35)} |'.center(width_calculated())
                  )
        print(("-" * 177).center(width_calculated()))
        self.ID = str()
        while not re.match(r"^[0-9]+$", self.ID):
            self.ID = input('Taper l ID du Joueur : ')
        return self.ID

    def list_player_in_game(self, list_player_object):
        """
        Generates an array of players in the tournament
        :param list_player_object:
        """
        cls()
        icon()
        print(f'{"Liste des Joueurs pour ce Tournoi".center(width_calculated())}\n')

        print(("=" * 150).center(width_calculated()))
        print(f'| {"Nom".center(35)} |'
              f'{"Prénom".center(35)} |'
              f'{"Date de Naissance".center(35)} |'
              f'{"Genre".center(35)} |'.center(width_calculated())
              )
        for player in list_player_object:
            print(("-" * 150).center(width_calculated()))
            print(f'| {player.name.center(35)} |'
                  f'{player.first_name.center(35)} |'
                  f'{str(player.date_born).center(35)} |'
                  f'{player.genre.center(35)} |'.center(width_calculated())
                  )
        print(("=" * 150).center(width_calculated()))
        input("Appuyer sur une Entrée pour continuer ...")

    def print_table_round(self, list_player_object, unique_round):
        """
        Generates a table of the tournament rounds
        :param list_player_object:
        :param unique_round:
        """
        cls()
        icon()
        print(f'{"Tournoi en cours".center(width_calculated())}\n')

        print(f'{"Tour1".center(width_calculated())}\n')
        print(f'{("=" * 96).center(width_calculated())}')
        for self.id1, self.id2 in unique_round:
            self.adverse1, self.adverse2 = "", ""
            for self.player in list_player_object:
                if self.id1 == self.player.id:
                    self.adverse1 = str(self.player.name + " " + self.player.first_name)
                elif self.id2 == self.player.id:
                    self.adverse2 = str(self.player.name + " " + self.player.first_name)
            print(f'|{self.adverse1.center(45)} VS {self.adverse2.center(45)}|'.center(width_calculated()))
        print(f'{("=" * 96).center(width_calculated())}')

    def insert_point_match(self, current_round, players_list):
        """
        Request the entry of the points of each player
        :param current_round:
        :param players_list:
        """
        print('\nInsérer les points du Tour :')
        for key in current_round:
            for self.player in players_list:
                if self.player.id == key:
                    self.point = " "
                    while not re.match(r"^[+-]?([0-9]*[.])?[0-9]+$", self.point):
                        self.point = input(f'Insérer les points pour {self.player.name} {self.player.first_name} : ')
                    self.point = float(self.point)
                    current_round[key] = self.point

    def print_table_tournament(self, list_player_object):
        """
        Display the list of players of a selected tournament
        :param list_player_object:
        """
        cls()
        icon()
        print(f'{"Liste des Joueurs pour ce Tournoi".center(width_calculated())}\n')

        print(("=" * 150).center(width_calculated()))
        print(f'| {"Nom".center(35)} |'
              f'{"Prénom".center(35)} |'
              f'{"Point total dans le Tournoi".center(35)} |'
              f'{"Rank".center(35)} |'.center(width_calculated())
              )
        for player in list_player_object:
            print(("-" * 150).center(width_calculated()))
            print(f'| {player.name.center(35)} |'
                  f'{player.first_name.center(35)} |'
                  f'{str(player.point).center(35)} |'
                  f'{str(player.rank).center(35)} |'.center(width_calculated())
                  )
        print(("=" * 150).center(width_calculated()))

    def change_rank(self, player):
        """
        Request new player rank at the end of the tournament
        :param player:
        :return:
        """
        print("\n")
        self.new_rank = " "
        while not re.match(r"^[0-9]+$", self.new_rank):
            self.new_rank = input(f'insérer le Nouveau Rang de {player.name} {player.first_name} : ')
        return int(self.new_rank)

    def director_comment(self):
        """
        Request the input of the tournament director's comment at the end of the tournament
        :return: text string
        """
        cls()
        icon()
        print('Espace reservé au Directeur du Tournoi \n'
              'Veuillez écrire un commentaire, une observation\n'
              'si vous ne souhaitez pas inscrire de commentaire, tapez Entrée'.center(width_calculated()))
        self.comment = input('commentaire : ')
        return self.comment