import warnings
from langchain_core._api.deprecation import LangChainPendingDeprecationWarning
warnings.filterwarnings("ignore", category=LangChainPendingDeprecationWarning)

from langgraph.graph import StateGraph, END
from app.graph.state import WorkflowState
from app.graph.nodes import (
    pm_node,
    retrieval_node,
    dev_node,
    qa_node,
    human_review_node,
    delivery_node
)

def route_entry_point(state: WorkflowState):
    current_status = state.get("status")
    if current_status in ["human_approved", "human_refused"]:
        return "human_review"
    if current_status == "spec_approved":
        return "retrieval"
    return "pm"

# --- Fonctions de Routage (Conditional Edges) ---
def route_after_pm(state: WorkflowState):
    current_status = state.get("status")
    if current_status in ["spec_incomplete", "spec_ready"]:
        return END
    return "retrieval"

def route_after_retrieval(state: WorkflowState):
    # Si un projet existe, on demande d'abord à l'humain (via le nœud de review)
    if state.get("existing_project"):
        return "human_review"
    return "dev"

def route_after_qa(state: WorkflowState):
    qa_res = state.get("qa_result", {})

    if not qa_res.get("is_complete_and_safe", False) and state.get("loop_count", 0) < state.get("max_iterations", 3):
        print(f"⚠️ Échec QA (Essai {state.get('loop_count')}/{state.get("max_iterations", 3)}). Retour au nœud de développement.")
        return "dev"

    return "human_review"

def route_after_human(state: WorkflowState):
    current_status = state.get("status")
    
    if current_status == "wait_human_review":
        return END

    if state.get("existing_project") and not state.get("generated_code"):
        if state.get("existing_project_approved") is True:
            return END 
        return "dev"

    if current_status == "human_approved":
        return "delivery"
        
    if current_status == "human_refused":
        return "pm"
        
    return END

# --- Assemblage du Graphe ---

graph = StateGraph(WorkflowState)

graph.add_node("pm", pm_node)
graph.add_node("retrieval", retrieval_node)
graph.add_node("dev", dev_node)
graph.add_node("qa", qa_node)
graph.add_node("human_review", human_review_node)
graph.add_node("delivery", delivery_node)

graph.set_conditional_entry_point(
    route_entry_point,
    {
        "pm": "pm",
        "retrieval": "retrieval",
        "human_review": "human_review"
    },
)

graph.add_conditional_edges(
    "pm",
    route_after_pm,
    {
        END: END,
        "retrieval": "retrieval",
    },
)

# Étape 1 : Choix après recherche vectorielle
graph.add_conditional_edges(
    "retrieval",
    route_after_retrieval,
    {
        "dev": "dev",
        "human_review": "human_review",
    },
)

# Étape 2 & 3 : Boucle Dev <-> QA (Loop 1)
graph.add_edge("dev", "qa")
graph.add_conditional_edges(
    "qa",
    route_after_qa,
    {
        "dev": "dev",
        "human_review": "human_review",
    },
)

# Étape 4 : Boucle de Feedback Humain (Loop 2) ou Clôture
graph.add_conditional_edges(
    "human_review",
    route_after_human,
    {
        "pm": "pm",
        "dev": "dev",
        "delivery": "delivery",
        END: END,
    },
)

# Maillon final : Après Delivery, c'est la fin du cycle
graph.add_edge("delivery", END)

compiled_graph = graph.compile()