# ============================================================
#  ACTIVITÉ : Héritage et affichage d'objets en Python
#  Nom : .......................................
#  Date : .......................................
# ============================================================
#
#  CONSIGNES GÉNÉRALES
#  -------------------
#  1. Complète chaque # TODO dans l'ordre, sans sauter d'étape.
#  2. Exécute ton code après CHAQUE TODO pour vérifier.
#  3. Les "# Attendu :" t'indiquent ce que ton programme doit
#     afficher une fois le TODO complété.
#  4. Ne regarde pas le corrigé avant d'avoir essayé.
#
# ============================================================


# ============================================================
#  PARTIE 1 — Classe mère : Animal
# ============================================================
class Animal:
    def __init__(self, nom):
        self.nom = nom

    def faire_du_bruit(self):
        return f"{self.nom} fait un bruit."

    # --------------------------------------------------------
    # TODO 1 : écris la méthode __str__ de Animal
    # --------------------------------------------------------
    # Elle doit renvoyer une chaîne destinée à un UTILISATEUR,
    # c'est-à-dire une phrase lisible en français.
    #
    # Format attendu :  "Animal nommé <nom>"
    #
    # Indice : utilise une f-string.
    #          Rappel : self.nom contient le nom de l'animal.
    #
    # Attendu :
    #   a = Animal("Rex")
    #   print(a)          ->  Animal nommé Rex
    #
    def __str__(self):
        # TODO 1 : à compléter
        pass

    # --------------------------------------------------------
    # TODO 2 : écris la méthode __repr__ de Animal
    # --------------------------------------------------------
    # Elle doit renvoyer une chaîne destinée à un DÉVELOPPEUR,
    # c'est-à-dire quelque chose qui ressemble à du code Python
    # et qui pourrait recréer l'objet.
    #
    # Format attendu :  Animal(nom='Rex')
    #
    # Indices :
    #   - Utilise self.__class__.__name__ pour obtenir le nom
    #     de la classe ("Animal", puis "Chien", etc.).
    #   - Utilise {self.nom!r} pour obtenir 'Rex' AVEC les
    #     guillemets (le !r applique repr() à la valeur).
    #
    # Attendu :
    #   a = Animal("Rex")
    #   print(repr(a))    ->  Animal(nom='Rex')
    #
    def __repr__(self):
        # TODO 2 : à compléter
        pass


# ============================================================
#  PARTIE 2 — Classe fille : Chien
# ============================================================
class Chien(Animal):
    def __init__(self, nom, race):
        super().__init__(nom)   # initialise self.nom via Animal
        self.race = race        # attribut propre au Chien

    def faire_du_bruit(self):
        # Redéfinition : le chien aboie au lieu de "faire un bruit"
        return f"{self.nom} aboie."

    def mordre(self):
        return f"{self.nom} mord."

    # --------------------------------------------------------
    # TODO 3 : écris la méthode __str__ de Chien
    # --------------------------------------------------------
    # Objectif : ÉTENDRE le __str__ de Animal, sans le recopier.
    #
    # Format attendu :  "Animal nommé Médor, race Berger allemand"
    #
    # Indices :
    #   - Commence par appeler super().__str__() pour récupérer
    #     la partie "Animal nommé Médor".
    #   - Ajoute ensuite ", race " suivi de self.race.
    #   - ATTENTION : on ne réécrit PAS "Animal nommé ..." à la
    #     main. On le RÉUTILISE via super().
    #
    # Attendu :
    #   c = Chien("Médor", "Berger allemand")
    #   print(c)          ->  Animal nommé Médor, race Berger allemand
    #
    def __str__(self):
        # TODO 3 : à compléter
        pass

    # --------------------------------------------------------
    # TODO 4 : écris la méthode __repr__ de Chien
    # --------------------------------------------------------
    # Objectif : RÉÉCRIRE complètement le __repr__ pour refléter
    #            les attributs RÉELS de la classe Chien.
    #
    # Format attendu :  Chien(nom='Médor', race='Berger allemand')
    #
    # Indices :
    #   - Contrairement à __str__, on ne réutilise PAS
    #     super().__repr__() ici : le résultat serait incohérent.
    #   - Utilise !r pour les valeurs texte.
    #
    # Attendu :
    #   c = Chien("Médor", "Berger allemand")
    #   print(repr(c))    ->  Chien(nom='Médor', race='Berger allemand')
    #
    def __repr__(self):
        # TODO 4 : à compléter
        pass


# ============================================================
#  PARTIE 3 — Classe fille : Chat
# ============================================================
class Chat(Animal):
    def __init__(self, nom, couleur):
        super().__init__(nom)
        self.couleur = couleur

    def faire_du_bruit(self):
        return f"{self.nom} miaule."

    # --------------------------------------------------------
    # TODO 5 : écris la méthode __str__ de Chat
    # --------------------------------------------------------
    # Format attendu :  "Animal nommé Titi, couleur Gris"
    # (Même logique que pour Chien, mais avec "couleur".)
    #
    def __str__(self):
        # TODO 5 : à compléter
        pass

    # --------------------------------------------------------
    # TODO 6 : écris la méthode __repr__ de Chat
    # --------------------------------------------------------
    # Format attendu :  Chat(nom='Titi', couleur='Gris')
    #
    def __repr__(self):
        # TODO 6 : à compléter
        pass


# ============================================================
#  PARTIE 4 — Vérification
# ============================================================
# Exécute ce bloc une fois tous les TODO complétés.
# Compare les résultats avec les commentaires "Attendu".
# ============================================================
if __name__ == "__main__":
    medor = Chien("Médor", "Berger allemand")
    titi  = Chat("Titi", "Gris")

    print("---- faire_du_bruit (polymorphisme) ----")
    for animal in [medor, titi]:
        print(animal.faire_du_bruit())
    # Attendu :
    #   Médor aboie.
    #   Titi miaule.

    print("\n---- __str__ (affichage utilisateur) ----")
    print(medor)   # Attendu : Animal nommé Médor, race Berger allemand
    print(titi)    # Attendu : Animal nommé Titi, couleur Gris

    print("\n---- __repr__ (affichage développeur) ----")
    print(repr(medor))   # Attendu : Chien(nom='Médor', race='Berger allemand')
    print(repr(titi))    # Attendu : Chat(nom='Titi', couleur='Gris')

    print("\n---- Dans une liste : c'est __repr__ qui s'affiche ----")
    print([medor, titi])
    # Attendu :
    # [Chien(nom='Médor', race='Berger allemand'), Chat(nom='Titi', couleur='Gris')]

    print("\n---- type() ----")
    print(type(medor))   # Attendu : <class '__main__.Chien'>
    print(type(titi))    # Attendu : <class '__main__.Chat'>