import logging
import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

import uvicorn
import asyncio
from contextlib import asynccontextmanager
from typing import List, Optional, Any, Dict
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from langchain_core.messages import HumanMessage
from agent.agent import get_agent
from agent.utils.mcp_helper import mcp_client
from agent.utils.reply_factory import build_replies
from config.settings import settings
from agent.utils.precalc_helper import save_archetype_to_backend

# Configuración de logs
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("agrota-agent-api")

# Configuración de prefijo según el cliente
client_name = settings.CLIENT_NAME or "agrota"
api_prefix = f"/api/v3/{client_name}"

@asynccontextmanager
async def lifespan(app: FastAPI):
    """Eventos de vida del servidor: arranque y cierre."""
    try:
        logger.info("🚀 Iniciando Agente AGROTA con LangGraph...")
        # Inicializar el agente (esto carga el grafo y persistencia)
        await get_agent()
        
        # Obtener herramientas MCP para validar conexión y mostrar al usuario
        logger.info("🛠️ Conectando con Servidor MCP...")
        tools = await mcp_client.get_tools_async()
        if tools:
            logger.info(f"✅ Tools detectadas: {[t.name for t in tools]}")
        else:
            logger.warning("⚠️ No se detectaron tools en el servidor MCP.")
            
        # Mostrar estado de configuración crítica
        token_status = "✅ Cargado" if settings.WHATSAPP_ACCESS_TOKEN else "❌ NO ENCONTRADO"
        logger.info(f"📱 WhatsApp Token: {token_status}")
        
        logger.info("✅ Entorno de Agente cargado exitosamente.")
    except Exception as e:
        logger.error(f"⚠️ Error crítico en arranque: {e}")
    
    yield
    
    logger.info("🛑 Apagando Agente AGROTA...")

app = FastAPI(
    title=f"Agrota Felizia Agent - {client_name.upper()}", 
    version="3.5.0",
    docs_url=f"{api_prefix}/docs",
    openapi_url=f"{api_prefix}/openapi.json",
    lifespan=lifespan
)

# Esquemas de entrada y salida
class ChatRequest(BaseModel):
    id: str  # ID de sesión (Normalmente el número de WhatsApp)
    username: Optional[str] = "Usuario"
    message: str
    context: Optional[dict] = None # BackAgrota envía contexto como dict

class ChatResponse(BaseModel):
    status: str = "success"
    replies: List[Dict[str, Any]]
    intencion: Optional[str] = None
    usage: Optional[Dict[str, int]] = None
    dax_query: Optional[str] = None
    success_message: Optional[str] = None

@app.get("/")
async def root():
    return {"status": "online", "client": client_name, "version": "3.5.0"}

@app.post(f"{api_prefix}/chat", response_model=ChatResponse)
async def chat_endpoint(request: ChatRequest):
    """Endpoint principal para procesamiento de mensajes con LangGraph."""
    # Color verde brillante \033[92m
    logger.info(f"\033[92m📥 [Mensaje Usuario] {request.id}: {request.message}\033[0m")
    
    try:
        agent = await get_agent()
        
        # Preparar el estado inicial
        user_message = request.message
        user_name = request.username
        user_position = ""
        
        # Extraer datos del contexto si existen (enviados por BackAgrota)
        if request.context:
            user_name = request.context.get("userName", user_name)
            user_position = request.context.get("userPosition", "")

        state = {
            "messages": [HumanMessage(content=user_message)],
            "user_id": request.id,
            "user_name": user_name,
            "user_role": user_position # Sincronizamos user_position como el rol para el PDF
        }
        
        # Configuración de persistencia (Thread ID de LangGraph)
        config = {"configurable": {"thread_id": request.id}}
        
        # Ejecutar flujo del Grafo
        result = await agent.ainvoke(state, config=config)
        
        # Extraer respuesta textual e intención
        last_msg = result["messages"][-1]
        agent_response = last_msg.content if last_msg else ""
        intencion = result.get("intencion", "UNKNOWN")
        
        logger.info(f"🤖 [Felizia] Intención: {intencion}")

        # Construir respuestas para WhatsApp
        interactive_data = result.get("interactive_data")
        is_powerbi_intent = intencion in ["UB_PRESUPUESTO", "CARTERA", "TALENTO_HUMANO"]
        
        if interactive_data:
            # Si el agente generó texto pero también hay un menú, los combinamos
            replies = build_replies(interactive_data, add_rating=is_powerbi_intent)
        else:
            # Respuesta simple de texto
            replies = build_replies(agent_response, add_rating=is_powerbi_intent)

        return ChatResponse(
            status="success",
            replies=replies,
            intencion=intencion,
            usage=result.get("usage"),
            dax_query=result.get("dax_query"),
            success_message=result.get("ultimo_resultado")
        )

    except Exception as e:
        logger.error(f"❌ Error procesando chat: {e}")
        import traceback
        traceback.print_exc()
        raise HTTPException(status_code=500, detail=str(e))

# Estado en memoria para esperar correcciones de Felizia
AWAITING_CORRECTION: Dict[str, bool] = {}

# Compatibilidad con el formato antiguo de server.py (WhatsApp Webhook)
@app.post("/webhook")
async def webhook_compatibility(payload: Dict[str, Any]):
    """Captura el payload antiguo de BackAgrota y RETORNA el formato de Meta."""
    # Formato de entrada típico de Meta / BackAgrota simplificado
    logger.info(f"📩 Webhook Recibido (Compatibilidad): {payload.get('to')}")
    try:
        # Extraer mensaje: BackAgrota envía { "text": { "body": "hola" }, "to": "54..." }
        to_number = payload.get("to", "unknown")
        user_message = ""
        if "interactive" in payload:
            interactive = payload.get("interactive", {})
            if "button_reply" in interactive:
                user_message = interactive["button_reply"].get("id", "")
            elif "list_reply" in interactive:
                user_message = interactive["list_reply"].get("id", "")
        elif "text" in payload and "body" in payload["text"]:
            user_message = payload["text"]["body"]
        elif "audio" in payload and "id" in payload["audio"]:
            # Nueva lógica para manejar audios de WhatsApp
            from agent.utils.audio_handler import transcribe_whatsapp_audio
            user_message = await transcribe_whatsapp_audio(payload["audio"]["id"])
            logger.info(f"🎙️ [AUDIO TRANSCRITO] {to_number}: {user_message}")
            
            # Guardar log de depuración para Antigravity
            with open("transcription_debug.log", "a", encoding="utf-8") as f:
                import datetime
                f.write(f"{datetime.datetime.now()} | {to_number} | ID: {payload['audio']['id']} | Result: {user_message}\n")
        else:
            user_message = str(payload.get("message", payload))
            
        # Extraer variables de contexto de BackAgrota
        context = payload.get("context", {})

        # Interceptar respuesta si el bot está esperando corrección
        if AWAITING_CORRECTION.get(to_number):
            AWAITING_CORRECTION.pop(to_number, None)
            import httpx
            async def send_correction():
                try:
                    async with httpx.AsyncClient() as client:
                        await client.post("http://localhost:8085/lhia_agrota/webhook/calificaciones/corregir", json={
                            "numeroWhatsapp": to_number,
                            "resultadoEsperado": user_message
                        }, timeout=5.0)
                except Exception as inner_e:
                    logger.error(f"Error enviando corrección a BackAgrota: {inner_e}")
            asyncio.create_task(send_correction())

            return {
                "status": "success",
                "replies": [{"messaging_product": "whatsapp", "recipient_type": "individual", "to": to_number, "type": "text", "text": {"body": "Excelente observación, la voy a analizar y mejoraré mi conocimiento en brindarte respuestas exactas la próxima vez."}}],
                "intencion": "RATE_CORRECTION"
            }

        # Extracción segura de la valoración generada por BackAgrota
        is_rating = False
        rating_value = ""
        if "RATE_CORRECT" in user_message:
            is_rating = True
            rating_value = "RATE_CORRECT"
        elif "RATE_INCORRECT" in user_message:
            is_rating = True
            rating_value = "RATE_INCORRECT"

        # Interceptar botones de Calificación
        if is_rating:
            import httpx
            pregunta = ""
            respuesta = ""
            dax = ""
            intencion_final = ""
            
            try:
                agent = await get_agent()
                state = await agent.aget_state({"configurable": {"thread_id": to_number}})
                
                # Extraer datos técnicos para el aprendizaje
                dax = state.values.get("dax_query", "")
                intencion_final = state.values.get("intencion", "UNKNOWN")
                
                messages = state.values.get("messages", [])
                # Buscar el último intercambio de AI y Human
                if len(messages) >= 2:
                    # Encontrar el último mensaje humano
                    last_human_idx = -1
                    for idx in range(len(messages)-1, -1, -1):
                        msg_type = getattr(messages[idx], "type", "")
                        if type(messages[idx]) is dict:
                            msg_type = messages[idx].get("type", "")
                        if "human" in str(msg_type).lower():
                            last_human_idx = idx
                            pregunta = getattr(messages[idx], "content", messages[idx].get("content", "")) if type(messages[idx]) is dict else messages[idx].content
                            break
                    
                    # Encontrar el mensaje de AI correspondiente (el último mensaje de AI generado)
                    if last_human_idx != -1:
                        for idx in range(len(messages)-1, last_human_idx, -1):
                            msg_type = getattr(messages[idx], "type", "")
                            if type(messages[idx]) is dict:
                                msg_type = messages[idx].get("type", "")
                            if "ai" in str(msg_type).lower():
                                respuesta = getattr(messages[idx], "content", messages[idx].get("content", "")) if type(messages[idx]) is dict else messages[idx].content
                                break
            except Exception as state_err:
                logger.warning(f"No se pudo extraer historial para calificación (¿Redis desactivado?): {state_err}")

            async def process_rating_and_learning():
                try:
                    # 1. Enviar calificación al backend Java
                    async with httpx.AsyncClient() as client:
                        await client.post("http://localhost:8085/lhia_agrota/webhook/calificaciones/guardar", json={
                            "numeroWhatsapp": to_number,
                            "nombreUsuario": context.get("userName", "Usuario"),
                            "preguntaUsuario": pregunta,
                            "respuestaLhia": respuesta,
                            "calificacion": rating_value,
                            "resultadoEsperado": None
                        }, timeout=5.0)
                    
                    # 2. 🔥 APRENDIZAJE: Si es correcta, registrar como arquetipo
                    if rating_value == "RATE_CORRECT" and dax:
                        # Solo registrar si es una intención de reporte real
                        if intencion_final in ["UB_PRESUPUESTO", "CARTERA", "TALENTO_HUMANO"]:
                            logger.info(f"🧠 [LEARNING-BY-RATING] Registrando arquetipo validado: {pregunta[:50]}...")
                            await save_archetype_to_backend(pregunta, dax, intencion_final)
                            
                except Exception as inner_e:
                    logger.error(f"Error procesando calificación/aprendizaje: {inner_e}")
            
            asyncio.create_task(process_rating_and_learning())

            if rating_value == "RATE_INCORRECT":
                AWAITING_CORRECTION[to_number] = True
                return {
                    "status": "success",
                    "replies": [{"messaging_product": "whatsapp", "recipient_type": "individual", "to": to_number, "type": "text", "text": {"body": "Lamento la confusión. ¿Me podrías indicar cuál debió haber sido el resultado esperado?"}}],
                    "intencion": "RATE_INCORRECT"
                }
            else:
                return {
                    "status": "success",
                    "replies": [{"messaging_product": "whatsapp", "recipient_type": "individual", "to": to_number, "type": "text", "text": {"body": "¡Excelente! Seguiré a tu disposición."}}],
                    "intencion": "RATE_CORRECT"
                }
        
        chat_req = ChatRequest(
            id=to_number,
            username=context.get("userName", "Usuario"),
            message=user_message,
            context=context
        )
        
        # Llamar a la lógica del agente
        response = await chat_endpoint(chat_req)
        
        # --- FORMATEAR PARA BACKAGROTA ---
        # Añadir al formato todas las etiquetas necesarias para Meta a cada reply
        for reply in response.replies:
            reply["messaging_product"] = "whatsapp"
            reply["recipient_type"] = "individual"
            reply["to"] = to_number

        # BackAgrota (FeliziaService) espera un objeto mapeable a MessageResponseDto
        # que contenga una propiedad "status" y una lista "replies"
        response_json = {
            "status": response.status,
            "replies": response.replies,
            "intencion": response.intencion
        }
        
        # Enviar Logs a BackAgrota
        import httpx
        try:
            log_payload = {
                "userMessage": user_message,
                "daxQuery": response.dax_query or "",
                "successMessage": response.success_message or "",
                "lhiaMessage": response_json["replies"][0]["text"]["body"] if response_json["replies"] and response_json["replies"][0].get("text") else "",
                "status": response.status,
                "errorMessage": ""
            }
            async def send_log():
                try:
                    async with httpx.AsyncClient() as client:
                        await client.post("http://localhost:8085/lhia_agrota/webhook/log/powerbi", json=log_payload, timeout=5.0)
                except Exception as inner_e:
                    logger.error(f"Error enviando log a BackAgrota: {inner_e}")
            
            asyncio.create_task(send_log())
        except Exception as log_e:
            logger.error(f"Error preparando log a BackAgrota: {log_e}")
        
        import json
        # Imprime la respuesta en color cian/azul claro \033[96m
        formatted_json = json.dumps(response_json, indent=2, ensure_ascii=False)
        logger.info(f"\033[96m📤 [OUTPUT JSON FELIZIA]: \n{formatted_json}\033[0m")
        return response_json

    except Exception as e:
        logger.error(f"❌ Error en compatibilidad webhook: {e}")
        return {
            "messaging_product": "whatsapp",
            "to": payload.get("to", "unknown"),
            "type": "text",
            "text": { "body": f"⚠️ Error: {str(e)}" }
        }

if __name__ == "__main__":
    # Inicia en el puerto configurado (8086 por defecto en Agrota)
    port = settings.PORT
    uvicorn.run(app, host="0.0.0.0", port=port)
