import os
import os.path
import json

# !Attention! Pas de bibliothèque json à installer, elle est déjà disponible dans la
# bibliothèque standard de Python.

########### Fonctions données ###########

def chargement_json(nom_fichier):
    """Charge le contenu d'un fichier JSON dans un dictionnaire Python renvoyé"""
    with open(nom_fichier, "r", encoding="utf8") as curseur:
        return json.load(curseur)


def sauvegarde_json(dictionnaire, nom_fichier):
    """Sauvegarde le contenu d'un dictionnaire dans un fichier JSON"""
    with open(nom_fichier, "w", encoding="utf8") as curseur:
        json.dump(dictionnaire, curseur)


def est_dictionnaire(objet):
    """Teste si un objet est de type dictionnaire"""
    return isinstance(objet, dict)


##########################################


### Première fonction à implémenter après avoir découvert le fichier JSON agrégé
### Cf fichier `empreinte_ada_agr.json`
def total_simple(empreinte):
    """Fonction qui renvoie l'empreinte carbone totale d'un dictionnaire associant
    une empreinte carbone à des noms de catégories"""
    total = 0
    for valeur in empreinte.values():
        total += valeur
    return total

def test_total_simple():
    test_dico = {"a": 1, "b": 2, "c": 3}
    assert total_simple(test_dico) == 6
    empreinte_agr = chargement_json('empreinte_ada_agr.json')
    print(f"L'emprunte carbone totale d'Ada est de {total_simple(empreinte_agr)} kgCO2 (version simple)")

test_total_simple()

### Deuxième fonction : il faut la récursivité pour le cas des sous-catégories
### Cf fichier `empreinte_ada.json`
def total_rec(empreinte):
    """Fonction récursive qui renvoie l'empreinte carbone totale représentée
    par un dictionnaire dont les valeurs peuvent aussi être des dictionnaires"""
    total = 0
    for valeur in empreinte.values():
        if est_dictionnaire(valeur):
            total += total_rec(valeur)
        else:
            total += valeur
    return total


def test_total_rec():
    test_dico1 = {"a": 1, "d": 2}
    assert total_rec(test_dico1) == 3
    test_dico2 = {"a": {"b": 1, "c": 2}, "d": {"e": 3}}
    assert total_rec(test_dico2) == 6
    test_dico3 = {"Alimentation": {
        "Repas": {
            "Viande": {
                "Blanche": 1,
                "Rouge": 1
            },
            "Autre": 1
        },
        "Déchets": 1,
    },
    "Transport": {
        "Voiture": 1,
        "Train": 1
    }}
    assert total_rec(test_dico3) == 6
    empreinte = chargement_json('empreinte_ada.json')
    print(f"L'emprunte carbone totale d'Ada est de {total_rec(empreinte)} kgCO2 (version récursive)")
    # Le total est cohérent avec le résultat de total_simple !

test_total_rec()

# ==========================================
# Fonction à analyser et corriger (Question 3)
# ==========================================

def alerte_valeur_aberrante(empreinte, limite):
    """
    Fonction censée déterminer si au moins une valeur du dictionnaire
    dépasse strictement la limite donnée.
    """
    for categorie, valeur in empreinte.items():
        if est_dictionnaire(valeur):
            # si une valeur aberrante a été trouvée, on arrête de chercher et on retourne True
            if alerte_valeur_aberrante(valeur, limite):
                return True
        else:
            if valeur > limite:
                return True
    return False

# Question 3
# La fonction alerte_valeur_aberrante ne fonctionne pas correctement car si une
# valeur est un dictionnaire, elle retourne immédiatement le résultat de l'appel
# récursif, ce qui empêche de vérifier les autres catégories du dictionnaire.

def test_alerte_valeur_aberrante():
    # Cas de test 1 : dictionnaire simple sans sous-catégorie
    test_dico1 = {"a": 1, "b": 2, "c": 3}
    assert not alerte_valeur_aberrante(test_dico1, 4)
    assert alerte_valeur_aberrante(test_dico1, 2)
    # Cas de test 2 : dictionnaire avec des sous-catégorie "de profondeur 1"
    test_dico2 = {"a": {"b": 1, "c": 2}, "d": {"e": 3}, "f": 4}
    assert not alerte_valeur_aberrante(test_dico2, 4)
    assert alerte_valeur_aberrante(test_dico2, 2)
    # Cas de test 3 : donné dans le sujet
    empreinte = chargement_json('empreinte_ada.json')
    assert alerte_valeur_aberrante(empreinte, 1000)
    # Cas de test 4 : Cas limite du dictionnaire vide
    test_dico3 = {}
    assert not alerte_valeur_aberrante(test_dico3, 1)
    
test_alerte_valeur_aberrante()