from typing import Dict, List

from fastapi import APIRouter, UploadFile, File, HTTPException, Depends

from app.auth import get_current_user
from app.config import config
from app.core.dependencies import get_services
from app.core.services import AppServices
from app.services.soat_processing import (
    _agente_codificar_desde_soat_item,
    _generar_resumen_validacion,
    _parsear_respuesta_gemini_codigos,
    _validar_codigo_soat_con_documento,
)
from modules.processing.soat.soat_indexer import build_soat_index_from_pdf
from modules.processing.soat.soat_retriever import SOATRetriever

router = APIRouter()
@router.post("/soat/indexar_pdf")
async def soat_indexar_pdf(file: UploadFile = File(...), current_user = Depends(get_current_user), services: AppServices = Depends(get_services)):
    base_dir = services.base_dir
    mongo_storage = services.mongo_storage
    mongo = services.mongo_analyses
    client_groq = services.client_groq
    client_gemini = services.client_gemini
    retriever = services.cie10_retriever
    cups_retriever = services.cups_retriever
    soat_retriever = services.soat_retriever
    colombia_tz = services.colombia_tz
    soat_index_dir = "soat_faiss"
    try:
        contents = await file.read()
        tmp_path = base_dir / "_tmp_soat.pdf"
        with open(tmp_path, "wb") as f:
            f.write(contents)
        index_dir = build_soat_index_from_pdf(str(tmp_path), str(base_dir / soat_index_dir))
        services.soat_retriever = SOATRetriever(
            faiss_index_path=index_dir,
            groq_api_key=config.GROQ_API_KEY,
        )
        return {"mensaje": "Índice SOAT construido", "index_dir": index_dir}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/soat/codificar")
async def soat_codificar(data: dict, current_user = Depends(get_current_user), services: AppServices = Depends(get_services)):
    base_dir = services.base_dir
    mongo_storage = services.mongo_storage
    mongo = services.mongo_analyses
    client_groq = services.client_groq
    client_gemini = services.client_gemini
    retriever = services.cie10_retriever
    cups_retriever = services.cups_retriever
    soat_retriever = services.soat_retriever
    colombia_tz = services.colombia_tz
    soat_index_dir = "soat_faiss"
    if not soat_retriever:
        raise HTTPException(status_code=400, detail="Índice SOAT no inicializado")
    procedimientos = data.get("procedimientos") or []
    if not isinstance(procedimientos, list) or not procedimientos:
        raise HTTPException(status_code=400, detail="Procedimientos requeridos")
    resultados = soat_retriever.asignar_codigos(procedimientos)
    return {"resultados": resultados}

@router.post("/agente/codificar_desde_soat")
async def agente_codificar_desde_soat(payload: Dict, current_user = Depends(get_current_user), services: AppServices = Depends(get_services)):
    """Dado un conjunto de códigos/descripciones SOAT, propone CUPS y CIE‑10 óptimos con justificación y evidencia."""
    base_dir = services.base_dir
    mongo_storage = services.mongo_storage
    mongo = services.mongo_analyses
    client_groq = services.client_groq
    client_gemini = services.client_gemini
    retriever = services.cie10_retriever
    cups_retriever = services.cups_retriever
    soat_retriever = services.soat_retriever
    colombia_tz = services.colombia_tz
    soat_index_dir = "soat_faiss"
    items = payload.get("items") or []
    if not isinstance(items, list) or not items:
        raise HTTPException(status_code=400, detail="'items' debe ser una lista no vacía")
    resultados = []
    for item in items:
        try:
            resultados.append(_agente_codificar_desde_soat_item(item, soat_retriever, retriever, cups_retriever, client_groq, client_gemini))
        except Exception as e:
            resultados.append({"input": item, "error": str(e)})
    return {"resultados": resultados}

@router.post("/agente/analizar_hallazgos_qx")
async def agente_analizar_hallazgos_qx(payload: Dict, current_user = Depends(get_current_user), services: AppServices = Depends(get_services)):
    """
    Analiza Hallazgos y Descripción Quirúrgica para proponer CIE-10 y CUPS
    y devolverlos en formato compatible con la lista seleccionable de epicrisis.
    """
    hallazgos = str(payload.get("hallazgos") or "").strip()
    descripcion_procedimiento = str(payload.get("descripcion_procedimiento") or "").strip()
    max_chars = int(payload.get("max_chars") or 1800)

    if not hallazgos and not descripcion_procedimiento:
        raise HTTPException(
            status_code=400,
            detail="Debe enviar 'hallazgos' o 'descripcion_procedimiento'.",
        )

    partes = []
    if hallazgos:
        partes.append(f"Hallazgos quirurgicos: {hallazgos}")
    if descripcion_procedimiento:
        partes.append(f"Descripcion del procedimiento: {descripcion_procedimiento}")

    descripcion_agente = " | ".join(partes).strip()
    if len(descripcion_agente) > max_chars:
        descripcion_agente = descripcion_agente[:max_chars]

    resultado = await generar_codigos_desde_soat_gemini(
        {
            "descripciones": [
                {
                    "codigo_soat": "QX-HALLAZGOS",
                    "descripcion": descripcion_agente,
                }
            ]
        },
        current_user,
        services,
    )

    resultados = []
    for item in (resultado.get("resultados") or []):
        if not isinstance(item, dict):
            continue
        if item.get("error"):
            continue
        resultados.append(
            {
                **item,
                "fuente": "agente_hallazgos_qx",
            }
        )

    total_diagnosticos = 0
    total_procedimientos = 0
    for item in resultados:
        if item.get("cie10_principal"):
            total_diagnosticos += 1
        total_diagnosticos += len(item.get("cie10_secundarios") or [])

        if item.get("cups_principal"):
            total_procedimientos += 1
        total_procedimientos += len(item.get("cups_alternativos") or [])

    return {
        "mensaje": "Analisis de hallazgos quirurgicos completado",
        "fuente": "agente_hallazgos_qx",
        "resultados": resultados,
        "total_resultados": len(resultados),
        "total_diagnosticos": total_diagnosticos,
        "total_procedimientos": total_procedimientos,
    }

@router.post("/soat/chat")
async def soat_chat(payload: dict, current_user = Depends(get_current_user), services: AppServices = Depends(get_services)):
    base_dir = services.base_dir
    mongo_storage = services.mongo_storage
    mongo = services.mongo_analyses
    client_groq = services.client_groq
    client_gemini = services.client_gemini
    retriever = services.cie10_retriever
    cups_retriever = services.cups_retriever
    soat_retriever = services.soat_retriever
    colombia_tz = services.colombia_tz
    soat_index_dir = "soat_faiss"
    if not soat_retriever:
        raise HTTPException(status_code=400, detail="Índice SOAT no inicializado")
    mensaje = (payload.get("mensaje") or "").strip()
    if not mensaje:
        raise HTTPException(status_code=400, detail="'mensaje' es requerido")
    try:
        docs = soat_retriever.buscar(mensaje, k=15)
        contexto = "\n\n".join([f"(p.{d.metadata.get('page')}) {d.page_content[:1100]}" for d in docs])
        prompt = f"""
Eres un especialista en auditoría y codificación médica en Colombia. Responde usando EXCLUSIVAMENTE el contexto proporcionado del Manual SOAT 2024, citando páginas cuando corresponda. Si no hay información suficiente, dilo explícitamente.

Pregunta del usuario:
{mensaje}

Contexto SOAT (extractos):
{contexto}
"""
        resp = client_groq.chat.completions.create(
            model=config.GROQ_MODEL_SOAT,
            temperature=0.0,
            messages=[
                {"role": "system", "content": "Eres un asistente RAG estricto. No inventes contenido fuera del contexto."},
                {"role": "user", "content": prompt}
            ],
        )
        respuesta = resp.choices[0].message.content
        fuentes = [{"page": d.metadata.get("page"), "source": d.metadata.get("source")} for d in docs[:10]]
        return {"respuesta": respuesta, "fuentes": fuentes}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/soat/validar_factura")
async def validar_factura_soat(payload: Dict, current_user = Depends(get_current_user), services: AppServices = Depends(get_services)):
    """
    Valida códigos SOAT de una factura contra documentación quirúrgica.
    Propone CIE-10 y CUPS que justifiquen los códigos SOAT facturados.
    """
    base_dir = services.base_dir
    mongo_storage = services.mongo_storage
    mongo = services.mongo_analyses
    client_groq = services.client_groq
    client_gemini = services.client_gemini
    retriever = services.cie10_retriever
    cups_retriever = services.cups_retriever
    soat_retriever = services.soat_retriever
    colombia_tz = services.colombia_tz
    soat_index_dir = "soat_faiss"
    documento_quirurgico = payload.get("documento_quirurgico", "").strip()
    codigos_soat_factura = payload.get("codigos_soat_factura", [])
    
    if not documento_quirurgico:
        raise HTTPException(status_code=400, detail="Documento quirúrgico es requerido")
    
    if not codigos_soat_factura or not isinstance(codigos_soat_factura, list):
        raise HTTPException(status_code=400, detail="Códigos SOAT de factura son requeridos")
    
    try:
        # Extraer información estructurada del documento quirúrgico
        diagnosticos_prequx = _extraer_seccion_documento(documento_quirurgico, "DIAGNÓSTICOS PREQUIRÚRGICO")
        procedimientos = _extraer_seccion_documento(documento_quirurgico, "PROCEDIMIENTOS REALIZADOS")
        hallazgos = _extraer_seccion_documento(documento_quirurgico, "HALLAZGOS QUIRÚRGICOS")
        descripcion_proc = _extraer_seccion_documento(documento_quirurgico, "DESCRIPCIÓN DEL PROCEDIMIENTO")
        justificacion = _extraer_seccion_documento(documento_quirurgico, "JUSTIFICACIÓN DEL PROCEDIMIENTO")
        diagnosticos_postqx = _extraer_seccion_documento(documento_quirurgico, "DIAGNÓSTICOS POSTQUIRÚRGICO")
        
        # Procesar cada código SOAT de la factura
        resultados_validacion = []
        
        for codigo_soat_item in codigos_soat_factura:
            codigo_soat = codigo_soat_item.get("codigo", "").strip()
            descripcion_soat = codigo_soat_item.get("descripcion", "").strip()
            fecha = codigo_soat_item.get("fecha", "")
            cantidad = codigo_soat_item.get("cantidad", 1)
            valor = codigo_soat_item.get("valor", "")
            
            # Validar el código SOAT contra la documentación
            resultado_validacion = await _validar_codigo_soat_con_documento(
                codigo_soat=codigo_soat,
                descripcion_soat=descripcion_soat,
                diagnosticos_prequx=diagnosticos_prequx,
                procedimientos=procedimientos,
                hallazgos=hallazgos,
                descripcion_proc=descripcion_proc,
                justificacion=justificacion,
                diagnosticos_postqx=diagnosticos_postqx,
                soat_retriever=soat_retriever,
                retriever=retriever,
                cups_retriever=cups_retriever,
                client_groq=client_groq,
                client_gemini=client_gemini
            )
            
            resultado_validacion.update({
                "codigo_soat": codigo_soat,
                "descripcion_soat": descripcion_soat,
                "fecha": fecha,
                "cantidad": cantidad,
                "valor": valor
            })
            
            resultados_validacion.append(resultado_validacion)
        
        # Generar resumen de validación
        resumen = _generar_resumen_validacion(resultados_validacion, documento_quirurgico)
        
        return {
            "mensaje": "Validación de factura SOAT completada",
            "documento_quirurgico_procesado": {
                "diagnosticos_prequx": diagnosticos_prequx,
                "procedimientos": procedimientos,
                "hallazgos": hallazgos,
                "justificacion": justificacion
            },
            "validaciones": resultados_validacion,
            "resumen": resumen
        }
        
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Error validando factura SOAT: {str(e)}")

@router.post("/soat/generar_codigos_gemini")
async def generar_codigos_desde_soat_gemini(payload: Dict, current_user = Depends(get_current_user), services: AppServices = Depends(get_services)):
    """
    Nueva feature: Genera códigos CIE-10 y CUPS directamente desde descripciones SOAT usando Gemini.
    Este endpoint NO usa RAG, sino que confía en el conocimiento de Gemini para codificación médica.
    """
    base_dir = services.base_dir
    mongo_storage = services.mongo_storage
    mongo = services.mongo_analyses
    client_groq = services.client_groq
    client_gemini = services.client_gemini
    retriever = services.cie10_retriever
    cups_retriever = services.cups_retriever
    soat_retriever = services.soat_retriever
    colombia_tz = services.colombia_tz
    soat_index_dir = "soat_faiss"
    descripciones_soat = payload.get("descripciones", [])
    
    if not descripciones_soat or not isinstance(descripciones_soat, list):
        raise HTTPException(
            status_code=400, 
            detail="Se requiere una lista de descripciones SOAT"
        )
    
    if not client_gemini:
        raise HTTPException(
            status_code=503,
            detail="Gemini no está configurado. Configure GEMINI_API_KEY."
        )
    
    try:
        resultados = []
        
        for item in descripciones_soat:
            descripcion = item.get("descripcion", "").strip()
            codigo_soat = item.get("codigo_soat", "").strip()
            
            if not descripcion:
                resultados.append({
                    "codigo_soat": codigo_soat,
                    "descripcion": descripcion,
                    "error": "Descripción vacía"
                })
                continue
            
            # Prompt optimizado para que Gemini genere códigos médicos
            prompt = f"""
Eres un especialista en codificación médica en Colombia con conocimiento experto en:
- Sistema CIE-10 (Clasificación Internacional de Enfermedades)
- Sistema CUPS (Clasificación Única de Procedimientos en Salud)
- Manual SOAT 2024 y codificación de accidentes de tránsito

Se te proporciona una descripción de un procedimiento o diagnóstico del sistema SOAT.

╔══════════════════════════════════════════════════════════════╗
║ INFORMACIÓN DEL PROCEDIMIENTO/DIAGNÓSTICO                    ║
╚══════════════════════════════════════════════════════════════╝

Código SOAT: {codigo_soat if codigo_soat else "No especificado"}
Descripción: {descripcion}

╔══════════════════════════════════════════════════════════════╗
║ TU TAREA                                                      ║
╚══════════════════════════════════════════════════════════════╝

Genera los códigos médicos correspondientes siguiendo ESTRICTAMENTE este formato:

CÓDIGOS CIE-10 RECOMENDADOS:
----------------------------
PRINCIPAL:
• Código: [CIE-10]
  Descripción: [Descripción completa oficial CIE-10]
  Justificación: [Por qué este código es el más apropiado]

SECUNDARIOS:
• Código: [CIE-10]
  Descripción: [Descripción completa oficial CIE-10]
  Justificación: [Relación con el diagnóstico/procedimiento]

• Código: [CIE-10]
  Descripción: [Descripción completa oficial CIE-10]
  Justificación: [Relación con el diagnóstico/procedimiento]

CÓDIGOS CUPS RECOMENDADOS:
----------------------------
PRINCIPAL:
• Código: [6 dígitos CUPS]
  Descripción: [Descripción completa oficial CUPS]
  Justificación: [Por qué este procedimiento es el indicado]

ALTERNATIVOS:
• Código: [6 dígitos CUPS]
  Descripción: [Descripción completa oficial CUPS]
  Justificación: [Cuándo considerar este procedimiento]

• Código: [6 dígitos CUPS]
  Descripción: [Descripción completa oficial CUPS]
  Justificación: [Cuándo considerar este procedimiento]

ANÁLISIS CLÍNICO:
----------------------------
Coherencia diagnóstico-procedimiento:
[Explicación de por qué los códigos CIE-10 y CUPS propuestos son coherentes entre sí]

Consideraciones SOAT:
[Aspectos específicos relevantes para facturación SOAT]

Prevención de glosas:
[Recomendaciones para documentar adecuadamente estos códigos]

IMPORTANTE:
- Usa SOLO códigos reales y oficiales de CIE-10 y CUPS
- Los códigos CUPS deben tener exactamente 6 dígitos
- Los códigos CIE-10 deben seguir el formato estándar (letra + números + punto si aplica)
- Proporciona al menos 1 código principal de cada tipo
- Sé específico y preciso en las justificaciones
"""

            # Llamar a Gemini
            response = client_gemini.generate_content(prompt)
            respuesta_gemini = response.text
            
            # Parsear la respuesta para extraer códigos estructurados
            codigos_parseados = _parsear_respuesta_gemini_codigos(respuesta_gemini)
            
            resultados.append({
                "codigo_soat": codigo_soat,
                "descripcion": descripcion,
                "cie10_principal": codigos_parseados["cie10_principal"],
                "cie10_secundarios": codigos_parseados["cie10_secundarios"],
                "cups_principal": codigos_parseados["cups_principal"],
                "cups_alternativos": codigos_parseados["cups_alternativos"],
                "analisis_clinico": codigos_parseados["analisis_clinico"],
                "respuesta_completa": respuesta_gemini
            })
        
        return {
            "mensaje": "Códigos generados exitosamente",
            "total_procesados": len(resultados),
            "resultados": resultados
        }
        
    except Exception as e:
        print(f"❌ Error generando códigos con Gemini: {e}")
        raise HTTPException(
            status_code=500,
            detail=f"Error al generar códigos: {str(e)}"
        )
