import json
from typing import List, Dict
from fastapi import HTTPException
from openai import OpenAI
from logging import getLogger
from rapidfuzz import process, fuzz  # Recomendación: pip install rapidfuzz para búsquedas rápidas

# Asumiendo que estas importaciones existen en tu proyecto
from config.settings import OPENAI_API_KEY
from models.user import User
from services.data_service import data_bg_loaded
from services.openai_service.openai_tools import tools_list, tools

openai_client = OpenAI(api_key=OPENAI_API_KEY)
logger = getLogger(__name__)

# --- OPTIMIZACIÓN 1: MINI-RAG EN MEMORIA ---
# En lugar de enviar TODO, buscamos lo más relevante a la última pregunta.
def get_relevant_context(last_user_message: str, dataset: List[Dict], top_k: int = 5) -> str:
    if not last_user_message or not dataset:
        return ""
    
    # Extraemos solo las preguntas para buscar coincidencias
    questions = [item["q"] for item in dataset]
    
    # Buscamos las 'top_k' preguntas más similares a lo que dijo el usuario
    results = process.extract(last_user_message, questions, scorer=fuzz.WRatio, limit=top_k)
    
    # Construimos un contexto limpio en formato Markdown (consume menos tokens que JSON)
    context_str = "### INFORMACIÓN RELEVANTE DEL MENÚ:\n"
    for _, score, index in results:
        if score > 50: # Umbral de relevancia
            item = dataset[index]
            context_str += f"- P: {item['q']}\n  R: {item['ans']}\n"
            
    return context_str

async def generate_completion(messages_array: List[dict], user: User) -> str:
    if not OPENAI_API_KEY:
        raise HTTPException(status_code=500, detail="OpenAI API key missing.")

    # 1. Obtener el último mensaje del usuario para buscar contexto
    last_message_content = messages_array[-1].get("message", "") if messages_array else ""
    
    # 2. Filtrar la base de datos (Crucial para escalar)
    # Si la DB es gigante, aquí llamarías a tu Vector DB (pgvector). 
    # Por ahora, usamos el filtro inteligente en memoria.
    dynamic_context = get_relevant_context(last_message_content, data_bg_loaded)

    # 3. Construir el System Prompt
    system_prompt = f"""
### ROL
Eres IAKlein, el asistente virtual del Bar Klein 🍻. Amigo carismático, breve y experto.

### DIRECTRICES
- **Estilo:** Chat rápido, emojis, tono relajado.
- **Regla:** NO tomas pedidos. Diles: "Para pedir, Justo en el boton de abajo esta la tienda 😉".
- **Datos:** Usa SOLO la información provista abajo. Si no sabes, dilo con gracia.

{dynamic_context}
"""

    # 4. Formatear historial correctamente para la API de Chat
    # Convertimos tu array de dicts al formato nativo de OpenAI
    api_messages = [{"role": "system", "content": system_prompt}]
    
    # Tomamos los últimos 10 mensajes para mantener el contexto ligero
    for msg in messages_array[-10:]:
        role = "user" # Asumimos user por defecto, ajusta según tu lógica si tienes mensajes del bot guardados
        content = f"<{msg.get('username', 'User')}> {msg.get('message', '')}"
        api_messages.append({"role": role, "content": content})

    try:
        # Primera llamada al modelo
        completion = openai_client.chat.completions.create(
            model="gpt-4o-mini",
            messages=api_messages,
            temperature=0.7,
            tools=tools_list,
            tool_choice="auto",
        )

        message = completion.choices[0].message

        # --- OPTIMIZACIÓN 2: MANEJO DE TOOLS ROBUSTO ---
        if message.tool_calls:
            logger.info(f"Tool calls detected: {message.tool_calls}")
            
            # Agregamos la intención de llamada al historial
            api_messages.append(message)

            for tool_call in message.tool_calls:
                function_name = tool_call.function.name
                if function_name in tools:
                    # Ejecutar herramienta
                    func_args = json.loads(tool_call.function.arguments)
                    tool_result = tools[function_name](name=user.name, email=user.email, **func_args)
                    
                    # Agregar el resultado de la herramienta al historial
                    api_messages.append({
                        "role": "tool",
                        "tool_call_id": tool_call.id,
                        "content": str(tool_result)
                    })
                else:
                    logger.warning(f"Tool {function_name} not found.")

            # SEGUNDA LLAMADA: Para que la IA interprete el resultado de la tool y responda al usuario
            final_completion = openai_client.chat.completions.create(
                model="gpt-4o-mini",
                messages=api_messages
            )
            return final_completion.choices[0].message.content

        return message.content

    except Exception as e:
        logger.error(f"OpenAI Error: {e}")
        return "¡Ups! Se me cayó la bandeja con las cervezas. Pregúntame de nuevo en un segundo. 🍻"

def admin_completion(prompt: str, messages_array: List[dict]) -> str:

    """Generate OpenAI admin completion"""

    messages = list(map(lambda x: f'<{x.get("username", "unknown")}> {x.get("message", "")}', messages_array))


    if not OPENAI_API_KEY:

        logger.error("Error: OpenAI API key is not configured.")

        raise HTTPException(status_code=500, detail="OpenAI API key not configured on server.")



    try:

        completion = openai_client.chat.completions.create(

        model="gpt-4o-mini",

        messages=[

        {"role": "system", "content": f"""

        IAKlein es el asistente oficial del bar Klein 🍻 y siempre se comunica en un estilo de chat corto, tipo mensajería o IRC, con emojis y mucho carisma. Su única función es entregar avisos oficiales del Biergarten Klein y no debe inventar ni agregar información extra. Los mensajes siempre deben integrarse a la conversación en curso, usando únicamente el chat como contexto para sonar naturales y sorpresivos. Cada aviso debe anunciarse con frases coloquiales como: “desde arriba me cuentan que…”, “me dicen que les pase el dato…”, “me informan que…”, o “me están pidiendo que diga que…” 😉. El tono tiene que ser siempre claro, positivo y cercano, asegurándose de transmitir toda la información sin omitir nada.



        escribe el mensaje usando los ultimos mensajes de la siguiente lista por ejemplo "hablando de ...(conexion con el tema).. me dicen que...(mensaje oficial)..." o "me cuentan que...(mensaje oficial)..., hablando de ...(conexion con el tema)..."

        mensajes: {messages}"""},

        {"role": "user", "content": prompt}

        ],

        temperature=0.7,

        )

        response_content = completion.choices[0].message.content

        return response_content if response_content else "-1"

    except Exception as e:

        logger.error(f"Error calling OpenAI for admin completion: {e}")

        raise HTTPException(status_code=500, detail="Error al procesar tu solicitud con OpenAI.")

