import unittest
import random
from math import fabs

import names

from TP2.Charmeur import Charmeur
from TP2.Negociateur import Negociateur
from TP2.Objet import Objet
from TP2.Personnage import Personnage

words = open('/etc/dictionaries-common/words').readlines()


class TestNegociateur2(unittest.TestCase):

    def test_marge(self):

        def check_transaction(n: Negociateur, p: Personnage, m: float, s: str = None) -> None:

            object_list_copy = p.getObjets().copy()
            object_list_nego_copy = n.getObjets().copy()

            p_richesse_initiale = p.richesse
            n_richesse_initiale = n.richesse
            diff_richesse_initiale = p_richesse_initiale - n_richesse_initiale
            self.assertTrue(n.choisir_action(p))

            diff_richesse_finale = p.richesse-n.richesse

            op = [obj for obj in p.getObjets() if obj in object_list_nego_copy]
            on = [obj for obj in n.getObjets() if obj in object_list_copy]
            o = None

            if op:
                o = op[0]
            elif on:
                o = on[0]
            else:
                print(object_list_copy)
                print(p.getObjets())
                print(object_list_nego_copy)
                print(n.getObjets())

            self.assertIsNotNone(o, f"Aucun objet n'a été échangé {'' if s is None else f'({s})'}")

            if p_richesse_initiale > p.richesse: # Achat par le négociateur
                self.assertEqual(diff_richesse_initiale-o.valeur*(1+m)*2, diff_richesse_finale, f"Le négociateur n'a pas acheté avec la bonne marge {'' if s is None else f'({s})'}")
            else: # Vente par le négociateur
                self.assertEqual(diff_richesse_initiale+o.valeur*(1-m)*2, diff_richesse_finale, f"Le négociateur n'a pas vendu avec la bonne marge {'' if s is None else f'({s})'}")


        object_list_nego = [Objet(random.choice(words)) for _ in range(15)]
        n = Negociateur(names.get_full_name(), object_list_nego)

        # Personnage inconnu avec intelligence inférieure
        for _ in range(10):
            object_list = [Objet(random.choice(words)) for _ in range(2)]
            p1 = Personnage(names.get_full_name(), object_list)
            p1.intelligence = n.intelligence-1

            check_transaction(n, p1, 0.30, "Personnage inconnu avec intelligence inférieure")

        object_list_nego = [Objet(random.choice(words)) for _ in range(15)]
        n = Negociateur(names.get_full_name(), object_list_nego)

        # Personnage inconnu avec intelligence égale et obstination supérieure
        for _ in range(10):
            object_list = [Objet(random.choice(words)) for _ in range(2)]
            p1 = Personnage(names.get_full_name(), object_list)
            p1.intelligence = n.intelligence
            p1.obstination = n.obstination-1

            check_transaction(n, p1, 0.30, "Personnage inconnu avec intelligence égale et obstination supérieure")

        # Personnage connu avec amitié > 0 et avec intelligence inférieure
        for _ in range(10):
            object_list = [Objet(random.choice(words)) for _ in range(2)]
            p1 = Personnage(names.get_full_name(), object_list)
            p1.intelligence = n.intelligence-1
            n.amis[p1] = 0.1

            check_transaction(n, p1, 0.15, "Personnage connu avec amitié > 0 et avec intelligence inférieure")

        object_list_nego = [Objet(random.choice(words)) for _ in range(15)]
        n = Negociateur(names.get_full_name(), object_list_nego)

        # Personnage connu avec amitié > 0 avec intelligence égale et obstination supérieure
        for _ in range(10):
            object_list = [Objet(random.choice(words)) for _ in range(2)]
            p1 = Personnage(names.get_full_name(), object_list)
            p1.intelligence = n.intelligence
            p1.obstination = n.obstination-1
            n.amis[p1] = 0.1

            check_transaction(n, p1, 0.15, "Personnage connu avec amitié > 0 avec intelligence égale et obstination supérieure")

        object_list_nego = [Objet(random.choice(words)) for _ in range(15)]
        n = Negociateur(names.get_full_name(), object_list_nego)

        # Personnage connu avec amitié > 0 et avec intelligence inférieure
        for _ in range(10):
            object_list = [Objet(random.choice(words)) for _ in range(2)]
            p1 = Personnage(names.get_full_name(), object_list)
            p1.intelligence = n.intelligence-1
            n.amis[p1] = -0.1

            check_transaction(n, p1, 0.30, "Personnage connu avec amitié > 0 et avec intelligence inférieure")

        object_list_nego = [Objet(random.choice(words)) for _ in range(15)]
        n = Negociateur(names.get_full_name(), object_list_nego)

        # Personnage connu avec amitié > 0 avec intelligence égale et obstination supérieure
        for _ in range(10):
            object_list = [Objet(random.choice(words)) for _ in range(2)]
            p1 = Personnage(names.get_full_name(), object_list)
            p1.intelligence = n.intelligence
            p1.obstination = n.obstination-1
            n.amis[p1] = -0.1

            check_transaction(n, p1, 0.30, "Personnage connu avec amitié > 0 avec intelligence égale et obstination supérieure")

        # Charmeur quelconque
        for _ in range(100):
            object_list_nego = [Objet(random.choice(words)) for _ in range(2)]
            n = Negociateur(names.get_full_name(), object_list_nego)
            object_list = [Objet(random.choice(words)) for _ in range(2)]
            c = Charmeur(names.get_full_name(), object_list)
            if random.randint(0, 1) > 0:
                n.amis[c] = random.random()*2-1
            check_transaction(n, c, 0, "Charmeur")

        # Autres cas
        for _ in range(100):
            n = Negociateur(names.get_full_name(), [Objet(random.choice(words)) for _ in range(2)])
            p = Personnage(names.get_full_name(), [Objet(random.choice(words)) for _ in range(2)])
            if p.intelligence < n.intelligence:
                p.intelligence = n.intelligence
            if p.intelligence == n.intelligence:
                p.obstination = n.obstination+1

            if random.randint(0, 1) > 0:
                n.amis[c] = random.random()*2-1

            s = ''
            if c in n.amis:
                s += f'ami({n.amis[c]})'
            else:
                s += 'inconnu'

            if p.intelligence == n.intelligence:
                s += '/aussi intelligent'
            elif p.intelligence > n.intelligence:
                s += '/plus intelligent'

            if p.obstination <= n.obstination:
                s += '/moins obstiné'
            else:
                s += '/plus obstiné'

            check_transaction(n, p, 0,f"autres cas {s}")


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