import random
import unittest

from TD_Arbres.TableauTrie import TableauTrie


def random_tableauTriee(n: int) -> tuple[list, TableauTrie]:
    random_lst = [random.random() for _ in range(n)]
    random_lst.sort()
    random_lst.reverse()

    lst = TableauTrie()
    for v in random_lst:
        lst.insert(v)

    random_lst.reverse()
    return random_lst, lst


def tableautriee_to_list(ttrie: TableauTrie) -> list:
    """
    Convertit un objet de type `TableauTrie` en `list` Python
    :param ttrie: le `TableauTrie` à convertir
    :return: la `list`
    """
    if ttrie is None:
        return None
    else:
        return [i for i in ttrie._stockage]


class TestTableauTrie(unittest.TestCase):

    @unittest.skipIf(not hasattr(TableauTrie, 'insert'), "Il manque la méthode ListeTriee.insert()")
    def test_TableauTrie_insert(self):
        for _ in range(1000):
            n = random.randint(1, 20)
            random_list = [random.randint(0, 2 * n) for _ in range(n)]
            collection_triee = TableauTrie()

            for i in random_list:
                collection_triee.insert(i)

            liste_finale = tableautriee_to_list(collection_triee)
            random_list.sort()
            self.assertEqual(liste_finale, random_list, f"La liste n'est pas triée")

    @unittest.skipIf(not hasattr(TableauTrie, 'delete'), "Il manque la méthode ListeTriee.delete()")
    def test_TableauTrie_delete(self):
        for _ in range(100):
            n = random.randint(1, 20)
            t, collection_triee = random_tableauTriee(n)
            liste_copie = [i for i in t]
            random.shuffle(liste_copie)

            self.assertIsNone(collection_triee.delete(n),
                              f"ListeTriee.delete() doit renvoyer None pour des valeurs inexistantes")

            liste_reduite = None
            for i in liste_copie:
                collection_triee.delete(i)
                del (t[t.index(i)])
                liste_reduite = tableautriee_to_list(collection_triee)
                self.assertEqual(t, liste_reduite, f"La liste n'est pas triée ou l'élément {i} n'a pas été supprimé")

            self.assertEqual(t, [])
            self.assertEqual(liste_reduite, [])
            self.assertIsNone(collection_triee.delete(random.randint(1, 20)),
                              f"ListeTriee.delete() doit renvoyer None pour une liste vide")

    @unittest.skipIf(not hasattr(TableauTrie, 'contains'), "Il manque la méthode ListeTriee.contains()")
    def test_TableauTrie_contains(self):
        n = 20
        random_list_in = [random.random() for _ in range(n)]
        random_list_out = [random.random() + 1 for _ in range(n)]
        collection_triee = TableauTrie()

        for i in random_list_in:
            collection_triee.insert(i)

        liste_finale = tableautriee_to_list(collection_triee)
        random_list = random_list_out + random_list_in
        random.shuffle(random_list)

        for e in random_list:
            self.assertEqual(e in random_list_in, collection_triee.contains(e),
                             f"La vérification de présence de {e} donne une mauvaise réponse pour {collection_triee._stockage}")
            liste_temp = tableautriee_to_list(collection_triee)
            self.assertEqual(liste_temp, liste_finale, f'ListeTriee.contains() ne devrait pas modifier la liste')


if __name__ == '__main__':
    unittest.main(verbosity=2)
