"""
Definizione del grafo LangGraph — cuore dell'orchestrazione multi-agente.

Questo modulo:
1. Carica tutti gli artefatti dal disco (FAISS, LightFM, metadati)
2. Crea i nodi agente iniettando le dipendenze (factory pattern)
3. Definisce il grafo con routing condizionale:

    [Utente] → Router → agent_ricerca      → [Risposta]
                       → agent_recommender  → [Risposta]
                       → agent_saluti       → [Risposta]
                       → agent_default      → [Risposta]

Il Router decide la destinazione. Ogni agente risponde e il flusso termina (END).
Il MemorySaver mantiene la cronologia messaggi tra turni di conversazione.

Esporta: `app` (grafo compilato), importato da main.py.
"""

import warnings
warnings.filterwarnings("ignore")

from typing import TypedDict, Annotated
from langgraph.graph import StateGraph, END
from langgraph.graph.message import add_messages
from langgraph.checkpoint.memory import MemorySaver

from utils.llm import llm
from utils.loaders import load_product_retriever, load_router_retriever, load_recommender, load_metadata_lookup
from agents import (
    create_nodo_router, create_nodo_ricerca, create_nodo_recommender,
    nodo_saluti, nodo_default
)


# --- Definizione dello stato condiviso tra i nodi ---
class AgentState(TypedDict):
    messages: Annotated[list, add_messages]  # Cronologia messaggi (accumulativa)
    decision: str                             # Destinazione scelta dal Router
    resolved_query: str                       # Query riscritta dal Router con contesto conversazionale risolto


# --- Caricamento artefatti dal disco ---
print("--- Inizializzazione Sistema ---")
product_retriever = load_product_retriever()   # FAISS catalogo prodotti
router_retriever = load_router_retriever()     # FAISS esempi few-shot router
rec_model, rec_idx_map, rec_item_features = load_recommender()  # LightFM + mappature + features
metadata_lookup = load_metadata_lookup()       # ASIN → dettagli prodotto

# --- Creazione nodi agente (dependency injection) ---
nodo_router = create_nodo_router(llm, router_retriever)
nodo_ricerca = create_nodo_ricerca(llm, product_retriever)
nodo_recommender = create_nodo_recommender(rec_model, rec_idx_map, metadata_lookup, rec_item_features, product_retriever, llm)

# --- Costruzione grafo ---
workflow = StateGraph(AgentState)

# Registrazione nodi
workflow.add_node("router", nodo_router)
workflow.add_node("agent_saluti", nodo_saluti)
workflow.add_node("agent_ricerca", nodo_ricerca)
workflow.add_node("agent_recommender", nodo_recommender)
workflow.add_node("agent_default", nodo_default)

# Il Router e' il punto di ingresso
workflow.set_entry_point("router")

# Routing condizionale: il Router scrive "decision" nello stato,
# LangGraph usa quel valore per scegliere il prossimo nodo
workflow.add_conditional_edges("router", lambda x: x["decision"])

# Tutti gli agenti terminano il flusso dopo la risposta
workflow.add_edge("agent_saluti", END)
workflow.add_edge("agent_ricerca", END)
workflow.add_edge("agent_recommender", END)
workflow.add_edge("agent_default", END)

# Compila il grafo con il checkpointer per la memoria di sessione
memory = MemorySaver()
app = workflow.compile(checkpointer=memory)
