import logging
from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage
import httpx
from app.core.config import settings
from app.schemas.qa_report import QAEvaluation, StructureEvaluation
from app.llm.prompts import QA_AGENT_PROMPT, QA_STRUCTURE_AGENT_PROMPT
from app.sandbox.qa_client import run_project_qa

logger = logging.getLogger(__name__)

sync_client = httpx.Client(verify=False)
async_client = httpx.AsyncClient(verify=False)

async def run_qa_agent(project_title: str, dev_output: dict) -> QAEvaluation:
    """
    Agent QA : 
    Analyse le code généré à l'aide de l'API externe de la Sandbox (Semgrep uniquement),
    valide la structure minimale du projet à l'aide d'un second appel LLM,
    puis produit le rapport d'évaluation fusionné.
    """
    logger.info(f"[QA Agent] Début du processus d'audit statique pour le projet : {project_title}")
    
    repo_url = dev_output.get("repo_url")
    if not repo_url:
        logger.error("[QA Agent] Aucun URL de dépôt Git trouvé dans le dev_output.")
        return QAEvaluation(
            is_complete_and_safe=False,
            global_summary="Impossible de récupérer le code source (URL Git manquante).",
            technical_feedback=["L'agent de développement n'a pas fourni d'URL pour le dépôt Gitea."]
        )
    
    llm = ChatOpenAI(
        base_url=settings.llm_base_url,
        api_key=settings.llm_api_key,
        model=settings.llm_model_qa,
        temperature=0.1,
        max_retries=2,
        http_client=sync_client,
        http_async_client=async_client,
    )

    # 1. Exécution de l'analyse statique via le service Sandbox indépendant
    try:
        repo_name = repo_url.rstrip("/").split("/")[-1]
        logger.info(f"[QA Agent] Envoi du dépôt '{repo_name}' au conteneur d'analyse statique...")
        
        raw_results = await run_project_qa(repo_url=repo_url)
        
        logger.info(f"[QA Agent] 📊 Retour Sandbox Statis - Status : {'Succès' if raw_results.is_executable else 'Échec'}")
        logger.info(f"[QA Agent] 📊 Retour Sandbox - Nombre d'alertes de sécurité/qualité (Semgrep): {len(raw_results.issues)}")
        
    except Exception as e:
        logger.error(f"[QA Agent] ❌ Échec de la communication avec le conteneur de Scan : {str(e)}")
        return QAEvaluation(
            is_complete_and_safe=False,
            global_summary="Échec critique lors du traitement du rapport de scan statique.",
            technical_feedback=[f"L'API de la sandbox a échoué : {type(e).__name__}: {str(e)}"]
        )
    
    # 2. Premier appel LLM : Audit de sécurité (Semgrep)
    qa_evaluation = None
    try:
        logger.info("[QA Agent] Lancement de l'audit de sécurité et de qualité (Semgrep)...")
        structured_security_llm = llm.with_structured_output(QAEvaluation, strict=True)

        security_messages = [
            SystemMessage(content=QA_AGENT_PROMPT),
            HumanMessage(content=(
                f"PROJET À AUDITER : {project_title}\n"
                f"LIEN DU DÉPÔT : {repo_url}\n"
                f"RÉSULTATS DE L'ANALYSE STATIQUE DU CODE (Semgrep) :\n"
                f"{raw_results.model_dump_json(indent=2)}\n\n"
                f"Analyse ces failles, vulnérabilités et défauts de qualité de code, puis génère ton évaluation de sécurité au format structuré demandé."
            ))
        ]

        qa_evaluation = await structured_security_llm.ainvoke(security_messages)
        
    except Exception as e:
        logger.error(f"[QA Agent] ❌ Échec lors de l'audit de sécurité LLM : {type(e).__name__}: {str(e)}")
        qa_evaluation = QAEvaluation(
            is_complete_and_safe=False,
            global_summary="Erreur lors de la génération du rapport de sécurité par le LLM.",
            technical_feedback=[f"Le module de sécurité a échoué : {type(e).__name__}"]
        )

    # 3. Second appel LLM : Validation de la structure minimale (Arborescence)
    structure_evaluation = None
    try:
        logger.info("[QA Agent] Lancement de l'audit de conformité de l'arborescence...")
        structured_structure_llm = llm.with_structured_output(StructureEvaluation, strict=True)
        
        repo_structure = raw_results.runtime.stdout or "Arborescence non détectée ou vide."

        structure_messages = [
            SystemMessage(content=QA_STRUCTURE_AGENT_PROMPT),
            HumanMessage(content=(
                f"PROJET À ANALYSER : {project_title}\n"
                f"ARBORESCENCE DU RÉPERTOIRE CLONÉ :\n"
                f"{repo_structure}\n\n"
                f"Vérifie si la structure respecte les exigences minimales et fournis ton évaluation structurée."
            ))
        ]

        structure_evaluation = await structured_structure_llm.ainvoke(structure_messages)
        logger.info(f"[QA Agent] 📁 Structure détectée : {structure_evaluation.detected_language} | Valide : {structure_evaluation.is_valid}")

    except Exception as e:
        logger.error(f"[QA Agent] ❌ Échec lors de la validation de structure LLM : {type(e).__name__}: {str(e)}")
        structure_evaluation = StructureEvaluation(
            is_valid=False,
            detected_language="Inconnu",
            missing_elements=["Erreur d'analyse structurelle"],
            feedback="Le module d'analyse d'arborescence a rencontré une erreur de traitement."
        )

    # 4. Fusion des résultats des deux audits
    final_is_complete_and_safe = qa_evaluation.is_complete_and_safe and structure_evaluation.is_valid
    final_feedback = list(qa_evaluation.technical_feedback)
    if not structure_evaluation.is_valid:
        for missing in structure_evaluation.missing_elements:
            final_feedback.append(f"[Structure] Élément obligatoire manquant : {missing}")

    final_summary = (
        f"{qa_evaluation.global_summary}\n\n"
        f"--- 📁 Validation de la Structure ({structure_evaluation.detected_language}) ---\n"
        f"Statut : {'Conforme' if structure_evaluation.is_valid else 'Non conforme'}\n"
        f"Feedback : {structure_evaluation.feedback}"
    )

    if final_is_complete_and_safe:
        logger.info(f"[QA Agent] ✅ Projet '{project_title}' VALIDÉ (Sécurité & Structure OK).")
    else:
        logger.warning(f"[QA Agent] ❌ Projet '{project_title}' REJETÉ (Non-conformité détectée).")

    return QAEvaluation(
        is_complete_and_safe=final_is_complete_and_safe,
        global_summary=final_summary,
        technical_feedback=final_feedback
    )