import re
from datetime import datetime
from typing import Annotated

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

from app.auth import get_current_user
from app.core.dependencies import get_services
from app.core.logging import bind_log_context, get_logger
from app.core.services import AppServices
from app.models import UserInDB
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 = get_logger(__name__)
CurrentUser = Annotated[UserInDB, Depends(get_current_user)]
ServicesDep = Annotated[AppServices, Depends(get_services)]

_CIE10_INLINE_PATTERN = re.compile(
    r"^\s*(?P<codigo>[A-TV-Z]\d{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: Annotated[UploadFile, File(...)],
    current_user: CurrentUser,
    services: ServicesDep,
):
    # Deprecated for the primary dashboard/cases upload flow.
    # Kept temporarily for legacy surfaces outside the mini-batch migration scope.
    bind_log_context(username=current_user.username, document_type="pdf_upload")
    mongo_storage = services.mongo_storage
    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=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))


@router.post("/upload_documento_adicional")
async def upload_documento_adicional(
    file: Annotated[UploadFile, File(...)],
    tipo_documento: Annotated[str, Form(...)],
    current_user: CurrentUser,
    services: ServicesDep,
    nombre_paciente: Annotated[str | None, Form()] = None,
    case_key: Annotated[str | None, Form()] = None,
):
    """
    Sube y procesa un documento adicional (laboratorio, radiología, etc.)
    y lo asocia a un paciente existente o crea nueva asociación.
    """
    # Deprecated for the primary dashboard/cases upload flow.
    # Kept temporarily for legacy surfaces outside the mini-batch migration scope.
    try:
        bind_log_context(username=current_user.username, document_type=tipo_documento)
        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 "",
                case_key=str(case_key or "").strip(),
                provided_patient_name=str(nombre_paciente or "").strip(),
                ingestion_source="manual",
            )
        )
    except Exception as e:
        logger.exception("Error processing additional document")
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))

@router.post("/procesar_documento_quirurgico_cups")
async def procesar_documento_quirurgico_cups(
    documento_id: Annotated[str, Form(...)],
    current_user: CurrentUser,
    services: ServicesDep,
):
    """
    Procesa un documento quirúrgico existente y asigna códigos CUPS a sus procedimientos.
    """
    mongo = services.mongo_analyses
    cups_retriever = services.cups_retriever
    colombia_tz = services.colombia_tz
    try:
        bind_log_context(username=current_user.username, document_type="quirurgico")
        # Validar ID
        if not ObjectId.is_valid(documento_id):
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST1, 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=status.HTTP_404_NOT_FOUND, detail="Documento quirúrgico no encontrado o acceso denegado"
            )

        # Extraer procedimientos quirúrgicos
        procedimientos = extraer_procedimientos_quirurgicos(doc)

        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:
        logger.exception("Error procesando documento quirúrgico CUPS")
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
