import unittest
from math import fabs

from TP3.RandomObject import RandomObjet
from RandomPersonnage import create_random_personnage


class RandomObjectTest(unittest.TestCase):
    def test_cession(self):
        """
        Teste si la fonction `Objet.effetCession()` est bien implantée pour `RandomObjet
        :return: None
        """
        for _ in range(100):
            p1 = create_random_personnage()
            richesse_p1 = p1.richesse

            force_p1 = p1.force
            intelligence_p1 = p1.intelligence
            empathie_p1 = p1.empathie
            obstination_p1 = p1.obstination
            charisme_p1 = p1.charisme

            liste_objets_p1 = list(p1.getObjets())
            self.assertFalse(liste_objets_p1 is None or liste_objets_p1 == [])

            o = RandomObjet('Test Objet 1')
            if hasattr(p1, '_objets'):
                objets = p1._objets
            elif hasattr(p1, 'objets'):
                objets = p1.objets
            else:
                raise AttributeError(f"{type(p1)} n'a pas d'attribut `objets` ou `_objets`.")

            if isinstance(objets,list):
                objets.append(o)
            else:
                objets.add(o)

            o.effetCession(p1)()
            self.assertFalse(o in p1.getObjets(),
                             f"`{type(o)}.effetCession({type(p1)})()` n'enlève pas l'objet de `Personnage.objets`.")
            self.assertSetEqual(set(liste_objets_p1), set(p1.getObjets()),
                                f"`{type(o)}.effetCession({type(p1)})()` a des effets de bord indésirables sur "
                                f"`Personnage.objets`.")
            self.assertEqual(richesse_p1 + o.valeur, p1.richesse,
                             f"`{type(o)}.effetCession({type(p1)})()` n'ajuste pas correctement `Personnage._richesse`.")

            self.assertEqual(force_p1, p1.force,
                             f"`Objet.effetCession({type(p1)})()` modifie `Personnage._force`.")
            self.assertEqual(intelligence_p1, p1.intelligence,
                             f"`Objet.effetCession({type(p1)})()` modifie `Personnage._intelligence`.")
            self.assertEqual(empathie_p1, p1.empathie,
                             f"`Objet.effetCession({type(p1)})()` modifie `Personnage._empathie`.")
            self.assertEqual(obstination_p1, p1.obstination,
                             f"`Objet.effetCession({type(p1)})()` modifie `Personnage._obstination`.")
            self.assertEqual(charisme_p1, p1.charisme,
                             f"`Objet.effetCession({type(p1)})()` modifie `Personnage._charisme`.")

            richesse_p1 = p1.richesse
            o = RandomObjet('Test Objet 2')

            if isinstance(objets,list):
                objets.append(o)
            else:
                objets.add(o)

            prix_objet = 3.33333
            o.effetCession(p1)(prix=prix_objet)
            self.assertFalse(o in p1.getObjets(),
                             f"`{type(o)}.effetCession({type(p1)})(prix=value)` n'enlève pas l'objet de `Personnage.objets`.")
            self.assertSetEqual(set(liste_objets_p1), set(p1.getObjets()),
                                f"`{type(o)}.effetCession({type(p1)})(prix=value)` a des effets de bord indésirables sur `Personnage.objets`.")
            self.assertEqual(richesse_p1 + prix_objet, p1.richesse,
                             f"`{type(o)}.effetCession({type(p1)})(prix=value)` n'ajuste pas correctement `Personnage._richesse`.")

    def test_acquisition(self):
        """
        Teste si la fonction `Objet.effetAcquisition()` est bien implantée pour `RandomObjet`
        :return: None
        """
        for _ in range(100):
            p1 = create_random_personnage()
            richesse_p1 = p1.richesse

            force_p1 = p1.force
            intelligence_p1 = p1.intelligence
            empathie_p1 = p1.empathie
            obstination_p1 = p1.obstination
            charisme_p1 = p1.charisme

            liste_objets_p1 = list(p1.getObjets())
            self.assertFalse(liste_objets_p1 is None or liste_objets_p1 == [])

            o = RandomObjet('Acquisition Test 1')
            o.effetAcquisition(p1)()
            self.assertTrue(o in p1.getObjets(),
                            f"`Objet.effetAcquisition({type(p1)})()` n'ajoute pas l'objet à `Personnage.objets`.")

            liste_objets_p1.append(o)
            self.assertSetEqual(set(liste_objets_p1), set(p1.getObjets()),
                                f"`Objet.effetAcquisition({type(p1)})()` a des effets de bord indésirables sur `Personnage.objets`.")
            self.assertEqual(richesse_p1 - o.valeur, p1.richesse,
                             f"`Objet.effetAcquisition({type(p1)})()` n'ajuste pas correctement `Personnage._richesse`.")

            self.assertAlmostEqual(force_p1, p1.force, None,
                                   f"`Objet.effetAcquisition({type(p1)})()` modifie `Personnage._force` de façon excessive.", 1)
            self.assertAlmostEqual(intelligence_p1, p1.intelligence, None,
                                   f"`Objet.effetAcquisition({type(p1)})()` modifie `Personnage._intelligence` de façon excessive.", 1)
            self.assertAlmostEqual(empathie_p1, p1.empathie, None,
                                   f"`Objet.effetAcquisition({type(p1)})()` modifie `Personnage._empathie` de façon excessive.", 1)
            self.assertAlmostEqual(obstination_p1, p1.obstination, None,
                                   f"`Objet.effetAcquisition({type(p1)})()` modifie `Personnage._obstination` de façon excessive.", 1)
            self.assertAlmostEqual(charisme_p1, p1.charisme, None,
                                   f"`Objet.effetAcquisition({type(p1)})()` modifie `Personnage._charisme` de façon excessive.", 1)

            total_modif = fabs(force_p1 - p1.force) + fabs(intelligence_p1 - p1.intelligence) + fabs(
                empathie_p1 - p1.empathie) + \
                          fabs(obstination_p1 - p1.obstination) + fabs(charisme_p1 - p1.charisme)
            self.assertLess(0.0, total_modif, f"`Objet.effetAcquisition({type(p1)}()` ne semble pas modifier les attributs de `Personnage`.")

            richesse_p1 = p1.richesse
            o = RandomObjet('Acquisition Test 2')
            prix_objet = 3.33333
            o.effetAcquisition(p1)(prix=prix_objet)
            self.assertTrue(o in p1.getObjets(),
                            f"`Objet.effetAcquisition({type(p1)}(prix=value)` n'ajoute pas l'objet à `Personnage.objets`.")
            liste_objets_p1.append(o)
            self.assertSetEqual(set(liste_objets_p1), set(p1.getObjets()),
                                f"`Objet.effetAcquisition({type(p1)}(prix=value)` a des effets de bord indésirables sur `Personnage.objets`.")
            self.assertEqual(richesse_p1 - prix_objet, p1.richesse,
                             f"`Objet.effetAcquisition({type(p1)}(prix=value)` n'ajuste pas correctement `Personnage._richesse`.")


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