"""
Caricamento degli artefatti dal disco.

Ogni funzione carica un artefatto specifico dalla cartella artifacts/:
- load_product_retriever()  → indice FAISS catalogo prodotti
- load_router_retriever()   → indice FAISS esempi few-shot per il router
- load_recommender()        → modello LightFM + mappature + matrice features
- load_metadata_lookup()    → dizionario ASIN → dettagli prodotto

Tutte le funzioni gestiscono il caso in cui l'artefatto non esista,
restituendo None o un dizionario vuoto. Questo permette al sistema
di avviarsi anche con artefatti mancanti (funzionalita' degradata).
"""

import json
import pickle
import warnings
warnings.filterwarnings("ignore")

from langchain_huggingface import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS
from utils.config import (
    EMBEDDING_MODEL_NAME, FAISS_PRODUCT_INDEX, FAISS_ROUTER_INDEX,
    RECOMMENDER_MODEL_PATH, METADATA_PATH, PRODUCT_SEARCH_K, ROUTER_SEARCH_K
)

# Modello di embedding condiviso tra tutti gli indici FAISS
embeddings = HuggingFaceEmbeddings(model_name=EMBEDDING_MODEL_NAME)


def load_product_retriever():
    """Carica l'indice FAISS del catalogo prodotti (100k items).
    Restituisce un retriever LangChain che, data una query, ritorna i k prodotti piu' simili."""
    try:
        store = FAISS.load_local(FAISS_PRODUCT_INDEX, embeddings, allow_dangerous_deserialization=True)
        print("  Catalogo Prodotti: CARICATO")
        return store.as_retriever(search_kwargs={"k": PRODUCT_SEARCH_K})
    except Exception as e:
        print(f"  Catalogo Prodotti: NON TROVATO ({e})")
        return None


def load_router_retriever():
    """Carica l'indice FAISS degli esempi few-shot per il router (~2750 esempi).
    Restituisce un retriever che, data una query utente, trova gli esempi piu' simili
    con la relativa etichetta di destinazione (agent_ricerca, agent_recommender, ecc.)."""
    try:
        store = FAISS.load_local(FAISS_ROUTER_INDEX, embeddings, allow_dangerous_deserialization=True)
        print("  Cervello Router: CARICATO")
        return store.as_retriever(search_kwargs={"k": ROUTER_SEARCH_K})
    except Exception as e:
        print(f"  Cervello Router: NON TROVATO ({e})")
        return None


def load_recommender():
    """Carica il modello LightFM ibrido e le sue mappature.

    Il pickle contiene:
    - model: il modello LightFM addestrato
    - idx_to_item: mappa indice interno → ASIN
    - item_features_matrix: matrice sparsa delle feature (categorie + prezzo),
      necessaria per get_item_representations(). None se modello non ibrido.

    Ritorna: (model, idx_to_item, item_features_matrix)
    """
    try:
        with open(RECOMMENDER_MODEL_PATH, "rb") as f:
            package = pickle.load(f)
            model = package["model"]
            idx_map = package.get("idx_to_item", {})
            item_features = package.get("item_features_matrix", None)
        print("  Recommender Engine: CARICATO (LightFM ibrido)")
        return model, idx_map, item_features
    except Exception as e:
        print(f"  Recommender Engine: NON TROVATO ({e})")
        return None, {}, None


def load_metadata_lookup():
    """Carica i metadati dei 100k prodotti e li indicizza per ASIN.
    Restituisce un dizionario {ASIN: {title, brand, price, categories, image_url}}.
    Usato dal Recommender Agent per mostrare nomi prodotti reali."""
    try:
        with open(METADATA_PATH, "r", encoding="utf-8") as f:
            products = json.load(f)
        lookup = {p["asin"]: p for p in products}
        print(f"  Catalogo Metadati: CARICATO ({len(lookup)} prodotti)")
        return lookup
    except Exception as e:
        print(f"  Catalogo Metadati: NON TROVATO ({e})")
        return {}
