import networkx as nx
import pandas as pd
import logging
import streamlit as st
import json
from networkx.drawing.nx_agraph import read_dot

# Configuration Gitea
from config import DOT_FILE
from utils.gitea import (
    charger_schema_depuis_gitea
)


def extraire_chemins_depuis(G, source):
    chemins = []
    stack = [(source, [source])]
    while stack:
        (node, path) = stack.pop()
        voisins = list(G.successors(node))
        if not voisins:
            chemins.append(path)
        else:
            for voisin in voisins:
                if voisin not in path:
                    stack.append((voisin, path + [voisin]))
    return chemins


def extraire_chemins_vers(G, target, niveau_demande):
    chemins = []
    reverse_G = G.reverse()
    niveaux = nx.get_node_attributes(G, "niveau")
    stack = [(target, [target])]

    while stack:
        (node, path) = stack.pop()
        voisins = list(reverse_G.successors(node))
        if not voisins:
            chemin_inverse = list(reversed(path))
            contient_niveau = any(
                int(niveaux.get(n, -1)) == niveau_demande for n in chemin_inverse
            )
            if contient_niveau:
                chemins.append(chemin_inverse)
        else:
            for voisin in voisins:
                if voisin not in path:
                    stack.append((voisin, path + [voisin]))

    return chemins


def recuperer_donnees(graph, noeuds):
    donnees = []
    ics = {}

    for noeud in noeuds:
        try:
            operation, minerai = noeud.split('_', 1)
        except ValueError:
            logging.warning(f"Nom de nœud inattendu : {noeud}")
            continue

        if operation == "Traitement":
            try:
                fabrications = list(graph.predecessors(minerai))
                valeurs = [
                    int(float(graph.get_edge_data(f, minerai)[0].get('ics', 0)) * 100)
                    for f in fabrications
                    if graph.get_edge_data(f, minerai)
                ]
                if valeurs:
                    ics[minerai] = round(sum(valeurs) / len(valeurs))
            except Exception as e:
                logging.warning(f"Erreur criticité pour {noeud} : {e}")
                ics[minerai] = 50

    for noeud in noeuds:
        try:
            operation, minerai = noeud.split('_', 1)
            ihh_pays = int(graph.nodes[noeud].get('ihh_pays', 0))
            ihh_acteurs = int(graph.nodes[noeud].get('ihh_acteurs', 0))
            ics_val = ics.get(minerai, 50)
            ics_cat = 1 if ics_val <= 33 else (2 if ics_val <= 66 else 3)

            donnees.append({
                'categorie': operation,
                'nom': minerai,
                'ihh_pays': ihh_pays,
                'ihh_acteurs': ihh_acteurs,
                'ics_minerai': ics_val,
                'ics_cat': ics_cat
            })
        except Exception as e:
            logging.error(f"Erreur sur le nœud {noeud} : {e}", exc_info=True)

    return pd.DataFrame(donnees)


def recuperer_donnees_2(graph, noeuds_2):
    donnees = []
    for minerai in noeuds_2:
        try:
            missing = []
            if not graph.has_node(minerai):
                missing.append(minerai)
            if not graph.has_node(f"Extraction_{minerai}"):
                missing.append(f"Extraction_{minerai}")
            if not graph.has_node(f"Reserves_{minerai}"):
                missing.append(f"Reserves_{minerai}")

            if missing:
                print(f"⚠️ Nœuds manquants pour {minerai} : {', '.join(missing)} — Ignoré.")
                continue

            ivc = int(graph.nodes[minerai].get('ivc', 0))
            ihh_extraction_pays = int(graph.nodes[f"Extraction_{minerai}"].get('ihh_pays', 0))
            ihh_reserves_pays = int(graph.nodes[f"Reserves_{minerai}"].get('ihh_pays', 0))

            donnees.append({
                'nom': minerai,
                'ivc': ivc,
                'ihh_extraction': ihh_extraction_pays,
                'ihh_reserves': ihh_reserves_pays
            })
        except Exception as e:
            print(f"Erreur avec le nœud {minerai} : {e}")
    return donnees


def couleur_noeud(n, niveaux, G):
    niveau = niveaux.get(n, 99)
    attrs = G.nodes[n]

    # Niveau 99 : pays géographique avec isg
    if niveau == 99:
        isg = int(attrs.get("isg", -1))
        return (
            "darkred" if isg >= 60 else
            "orange" if isg >= 31 else
            "darkgreen" if isg >= 0 else
            "gray"
        )

    # Niveau 11 ou 12 connecté à un pays géographique
    if niveau in (11, 12, 1011, 1012):
        for succ in G.successors(n):
            if niveaux.get(succ) == 99:
                isg = int(G.nodes[succ].get("isg", -1))
                return (
                    "darkred" if isg >= 60 else
                    "orange" if isg >= 31 else
                    "darkgreen" if isg >= 0 else
                    "gray"
                )

    # Logique existante pour IHH / IVC
    if niveau in (10, 1010) and attrs.get("ihh_pays"):
        ihh = int(attrs["ihh_pays"])
        return (
            "darkgreen" if ihh <= 15 else
            "orange" if ihh <= 25 else
            "darkred"
        )
    elif niveau == 2 and attrs.get("ivc"):
        ivc = int(attrs["ivc"])
        return (
            "darkgreen" if ivc <= 15 else
            "orange" if ivc <= 30 else
            "darkred"
        )

    return "lightblue"

def charger_graphe():
    if "G_temp" not in st.session_state:
            try:
                if charger_schema_depuis_gitea(DOT_FILE):
                    st.session_state["G_temp"] = read_dot(DOT_FILE)
                    st.session_state["G_temp_ivc"] = st.session_state["G_temp"].copy()
                    dot_file_path = True
                else:
                    dot_file_path = False
            except Exception as e:
                st.error(f"Erreur de lecture du fichier DOT : {e}")
                dot_file_path = False
    else:
        dot_file_path = True

    if dot_file_path:
        return dot_file_path
    else:
        st.error("Impossible de charger le graphe pour cet onglet.")
        return dot_file_path
