from datetime import datetime
import logging
import re

from bson import ObjectId
from fastapi import APIRouter, UploadFile, File, Form, HTTPException, Depends
from fastapi.responses import JSONResponse

from app.auth import get_current_user
from app.core.dependencies import get_services
from app.core.services import AppServices
from app.services.clinical_document_service import ClinicalDocumentRequest
from app.services.clinical_processing import extraer_procedimientos_quirurgicos
from modules.data_collection.read_pdf import ReadPdf

router = APIRouter()
logger = logging.getLogger(__name__)

_CIE10_INLINE_PATTERN = re.compile(
    r"^\s*(?P<codigo>[A-TV-Z][0-9]{2}[0-9A-Z]?(?:\.[0-9A-Z]{1,2})?)\s*(?:[-:–—]\s*|\s+)(?P<descripcion>.+)$",
    flags=re.IGNORECASE,
)


def _extraer_cie10_inline(diagnostico: str):
    """
    Si el diagnostico ya viene con codigo CIE-10 al inicio
    (ej: 'S923 - Fractura...'), lo reutiliza sin llamar al RAG.
    """
    if not diagnostico:
        return None
    match = _CIE10_INLINE_PATTERN.match(diagnostico.strip())
    if not match:
        return None
    return {
        "codigo": match.group("codigo").upper(),
        "descripcion": match.group("descripcion").strip(),
    }

@router.post("/upload_pdf")
async def upload_pdf(file: UploadFile = File(...), current_user = Depends(get_current_user), services: AppServices = Depends(get_services)):
    templates = services.templates
    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
    try:
        contents = await file.read()
        pdf_text = ReadPdf.read(contents)  # Extraer texto del PDF
        mongo_storage.guardar_pdf(
            nombre_archivo=file.filename,
            contenido=pdf_text,
            usuario=current_user.username  # Asociar con el usuario autenticado
        )
        return JSONResponse(content={
            "message": f"Archivo '{file.filename}' procesado y almacenado correctamente.",
            "texto_extraido": pdf_text
        })
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/upload_documento_adicional")
async def upload_documento_adicional(
    file: UploadFile = File(...),
    tipo_documento: str = Form(...),
    nombre_paciente: str = Form(None),
    current_user = Depends(get_current_user),
    services: AppServices = Depends(get_services),
):
    """
    Sube y procesa un documento adicional (laboratorio, radiología, etc.)
    y lo asocia a un paciente existente o crea nueva asociación.
    """
    try:
        contents = await file.read()
        pdf_text = ReadPdf.read(contents)
        return services.clinical_document_service.process_and_persist(
            ClinicalDocumentRequest(
                raw_text=pdf_text,
                detected_type=tipo_documento,
                username=current_user.username,
                original_name=file.filename or "",
                provided_patient_name=nombre_paciente or "",
                ingestion_source="manual",
            )
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/procesar_documento_quirurgico_cups")
async def procesar_documento_quirurgico_cups(
    documento_id: str = Form(...),
    current_user = Depends(get_current_user),
    services: AppServices = Depends(get_services),
):
    """
    Procesa un documento quirúrgico existente y asigna códigos CUPS a sus procedimientos.
    """
    templates = services.templates
    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
    try:
        # Validar ID
        if not ObjectId.is_valid(documento_id):
            raise HTTPException(status_code=400, detail="ID de documento no válido")
        
        # Buscar el documento
        doc = mongo.collection.find_one({
            "_id": ObjectId(documento_id),
            "usuario": current_user.username,
            "tipo_documento": "quirurgico"
        })
        
        if not doc:
            raise HTTPException(
                status_code=404, 
                detail="Documento quirúrgico no encontrado o acceso denegado"
            )
        
        analisis_html = doc.get("analisis_html")
        if not analisis_html:
            raise HTTPException(
                status_code=400, 
                detail="El documento no tiene análisis HTML disponible"
            )
        
        # Extraer procedimientos quirúrgicos
        procedimientos = extraer_procedimientos_quirurgicos(analisis_html)
        
        if not procedimientos:
            return {
                "mensaje": "No se encontraron procedimientos quirúrgicos en el documento",
                "id_documento": documento_id,
                "procedimientos": [],
                "codigos_cups": []
            }
        
        # Asignar códigos CUPS
        df_cups = cups_retriever.asignar_codigos(procedimientos)
        cups_list = df_cups.to_dict(orient="records")
        
        # Actualizar el documento con los códigos CUPS
        mongo.collection.update_one(
            {"_id": ObjectId(documento_id)},
            {
                "$set": {
                    "codigos_cups": cups_list,
                    "fecha_actualizacion_cups": datetime.now(colombia_tz).isoformat()
                }
            }
        )
        
        return {
            "mensaje": "Códigos CUPS asignados exitosamente al documento quirúrgico",
            "id_documento": documento_id,
            "nombre_archivo": doc.get("nombre_archivo"),
            "nombre_paciente": doc.get("nombre_paciente"),
            "total_procedimientos": len(procedimientos),
            "procedimientos": procedimientos,
            "codigos_cups": cups_list
        }
        
    except HTTPException:
        raise
    except Exception as e:
        print(f"❌ Error procesando documento quirúrgico: {e}")
        raise HTTPException(status_code=500, detail=str(e))
