import argparse

from base_de_donnees_vectorielle.chargeur_corpus import charger_corpus
from base_de_donnees_vectorielle.decoupage import decouper_document
from base_de_donnees_vectorielle.embeddings import calculer_embedding, charger_modele
from base_de_donnees_vectorielle.modele import ChunkVecteur
from base_de_donnees_vectorielle.recuperation import creer_document, parcourir_site, sauvegarder_document
from base_de_donnees_vectorielle.requeteur import rechercher
from base_de_donnees_vectorielle.stockage import charger_base, sauvegarder_base

def recuperer(url: str) -> None:
    """
    Récupère une page HTML, en extrait le texte nettoyé
    et sauvegarde le résultat dans le répertoire corpus.

    :param url: URL du document HTML à récupérer.
    """
    document = creer_document(url)
    chemin = sauvegarder_document(document, "corpus")
    print(f"Document sauvegardé dans : {chemin}")


def parcourir(url_depart: str, nombre_pages: int) -> None:
    """
    Parcourt un site Web à partir d'une URL de départ,
    récupère plusieurs pages et les sauvegarde dans le corpus.

    :param url_depart: URL de départ de l'exploration.
    :param nombre_pages: Nombre maximal de pages à explorer.
    """
    documents = parcourir_site(url_depart=url_depart,
                               nombre_pages=nombre_pages,
                               )

    for document in documents:
        chemin = sauvegarder_document(document, "corpus")
        print(f"Document sauvegardé dans : {chemin}")

    print(f"{len(documents)} document(s) récupéré(s).")


def indexer() -> None:
    """
    Construit la base vectorielle à partir des documents présents
    dans le répertoire corpus, puis la sauvegarde dans db/vector_db.json.
    """
    documents = charger_corpus("corpus")
    modele = charger_modele()
    base: list[ChunkVecteur] = []

    for document in documents:
        chunks = decouper_document(document)

        for identifiant_chunk, texte_chunk in chunks:
            embedding = calculer_embedding(texte_chunk, modele)
            base.append(
                ChunkVecteur(
                    ref_document=document.url,
                    id_chunk=identifiant_chunk,
                    texte=texte_chunk,
                    embedding=embedding,
                )
            )

    sauvegarder_base(base, "db/vector_db.json")
    print(f"Base vectorielle créée : {len(base)} chunks indexés")


def rechercher_documents(phrase: str) -> None:
    """
    Recherche les chunks les plus pertinents pour une phrase donnée
    dans la base vectorielle existante.

    :param phrase: Requête textuelle de l'utilisateur.
    """
    base = charger_base("db/vector_db.json")
    modele = charger_modele()
    resultats = rechercher(phrase, base, modele)

    for resultat in resultats:
        print("-" * 60)
        print(f"Score    : {resultat.score:.4f}")
        print(f"Document : {resultat.ref_document}")
        print(f"Chunk    : {resultat.id_chunk}")
        print(f"Texte    : {resultat.texte}")


def construire_parseur() -> argparse.ArgumentParser:
    """
    Construit et configure le parseur d'arguments.

    :return: Parseur argparse configuré.
    """
    parseur = argparse.ArgumentParser(
        description="Mini moteur RAG : récupération, parcours, indexation et recherche",
    )

    sous_commandes = parseur.add_subparsers(
        dest="commande",
        required=True,
    )

    parseur_recuperer = sous_commandes.add_parser(
        "recuperer",
        help="Récupère une page HTML et la stocke dans le corpus",
    )
    parseur_recuperer.add_argument(
        "url",
        type=str,
        help="URL du document à récupérer",
    )

    parseur_parcourir = sous_commandes.add_parser(
        "parcourir",
        help="Explore plusieurs pages à partir d'une URL de départ",
    )
    parseur_parcourir.add_argument(
        "url_depart",
        type=str,
        help="URL de départ de l'exploration",
    )
    parseur_parcourir.add_argument(
        "nombre_pages",
        type=int,
        help="Nombre maximal de pages à explorer",
    )

    sous_commandes.add_parser(
        "indexer",
        help="Construit la base vectorielle à partir du corpus",
    )

    parseur_rechercher = sous_commandes.add_parser(
        "rechercher",
        help="Recherche dans la base vectorielle",
    )
    parseur_rechercher.add_argument(
        "requete",
        type=str,
        nargs="+",
        help="Phrase de requête",
    )

    return parseur


def main() -> None:
    """
    Point d'entrée principal du programme avec gestion des arguments CLI.
    """
    parseur = construire_parseur()
    arguments = parseur.parse_args()

    if arguments.commande == "recuperer":
        recuperer(arguments.url)

    elif arguments.commande == "parcourir":
        parcourir(
            url_depart=arguments.url_depart,
            nombre_pages=arguments.nombre_pages,
        )

    elif arguments.commande == "indexer":
        indexer()

    elif arguments.commande == "rechercher":
        phrase = " ".join(arguments.requete)
        rechercher_documents(phrase)


if __name__ == "__main__":
    main()
