from datetime import datetime

from bson import ObjectId
from fastapi import APIRouter, HTTPException, Request
from fastapi.responses import HTMLResponse
from starlette import status

from app.case_epicrisis.application.cost_ordering import COST_ORDER_VERSION
from app.case_epicrisis.domain.models import RecomendacionMedica
from app.services.clinical_processing import formatear_medicamento_canonico, normalizar_lista_medicamentos

from .common import (
    CurrentUser,
    ServicesDep,
    _get_epicrisis_pdf_cache_collection,
    _inject_print_script,
    logger,
)


router = APIRouter()


def _normalize_text_list(values):
    if not isinstance(values, list):
        return []
    clean = []
    for item in values:
        text = str(item or "").strip()
        if text:
            clean.append(text)
    return clean


def _normalize_procedure_list(values):
    if not isinstance(values, list):
        return []
    clean = []
    for item in values:
        if isinstance(item, dict):
            code = str(item.get("codigo_cups") or item.get("codigo") or "").strip()
            description = str(
                item.get("descripcion") or item.get("procedimiento") or item.get("concepto") or ""
            ).strip()
            text = " - ".join(value for value in (code, description) if value)
        else:
            text = str(item or "").strip()
        if text:
            clean.append(text)
    return clean


def _normalize_classified_procedure_list(values):
    clean = []
    valid_classifications = {"quirurgico", "no_quirurgico"}
    for item in values if isinstance(values, list) else []:
        if not isinstance(item, dict):
            continue
        classification = str(item.get("clasificacion") or "").strip()
        if classification not in valid_classifications:
            continue
        code = str(item.get("codigo_cups") or item.get("codigo") or "").strip()
        description = str(
            item.get("descripcion") or item.get("procedimiento") or item.get("concepto") or ""
        ).strip()
        if not code and not description:
            continue
        clean.append(
            {
                "codigo_cups": code,
                "descripcion": description,
                "clasificacion": classification,
            }
        )
    return clean


def _normalize_dict_list(values):
    if not isinstance(values, list):
        return []
    return [item for item in values if isinstance(item, dict)]


def _normalize_recommendations(values):
    recommendations = []
    for item in values if isinstance(values, list) else []:
        if not isinstance(item, dict):
            continue
        try:
            recommendation = RecomendacionMedica.model_validate(item)
        except ValueError:
            continue
        recommendations.append(recommendation.model_dump(mode="json", exclude_none=True))
    return recommendations


@router.post("/epicrisis/pdf_cache")
async def guardar_epicrisis_pdf_cache(
    request: Request,
    current_user: CurrentUser,
    services: ServicesDep,
):
    mongo = services.mongo_analyses
    try:
        payload = await request.json()
        if not isinstance(payload, dict):
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Payload invalido")

        html_pdf = str(payload.get("html_pdf") or "").strip()
        if not html_pdf:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST, detail="El campo 'html_pdf' es obligatorio"
            )

        nombre_paciente = str(payload.get("nombre_paciente") or "").strip() or "desconocido"
        case_key = str(payload.get("case_key") or "").strip() or None
        epicrisis_base_id = str(payload.get("epicrisis_base_id") or "").strip() or None
        historia_id = str(payload.get("historia_id") or "").strip() or None
        quirurgico_id = str(payload.get("quirurgico_id") or "").strip() or None
        factura_id = str(payload.get("factura_id") or "").strip() or None
        notas_medicas = payload.get("notas_medicas")
        if not isinstance(notas_medicas, dict):
            notas_medicas = {}

        diagnostics = _normalize_text_list(payload.get("diagnosticos"))
        classified_procedures = _normalize_classified_procedure_list(
            payload.get("procedimientos_clasificados")
        )
        procedures = _normalize_procedure_list(
            classified_procedures
            if isinstance(payload.get("procedimientos_clasificados"), list)
            else payload.get("procedimientos")
        )
        medicamentos_detallados = normalizar_lista_medicamentos(
            payload.get("medicamentos"), fuente="cache_pdf"
        )
        cache_collection = _get_epicrisis_pdf_cache_collection(mongo)
        insert_result = cache_collection.insert_one(
            {
                "usuario": current_user.username,
                "tipo_documento": "epicrisis_pdf_cache",
                "nombre_paciente": nombre_paciente,
                "case_key": case_key,
                "epicrisis_base_id": epicrisis_base_id,
                "historia_id": historia_id,
                "quirurgico_id": quirurgico_id,
                "factura_id": factura_id,
                "orden_costo_version": COST_ORDER_VERSION,
                "fecha_guardado": datetime.now(),
                "html_pdf": html_pdf,
                "resumen_clinico": str(payload.get("resumen_clinico") or ""),
                "resumen_clinico_parrafos": _normalize_text_list(
                    payload.get("resumen_clinico_parrafos")
                ),
                "recomendaciones_medicas": _normalize_recommendations(
                    payload.get("recomendaciones_medicas")
                ),
                "antecedentes": _normalize_text_list(payload.get("antecedentes")),
                "hallazgos_quirurgicos": str(payload.get("hallazgos_quirurgicos") or ""),
                "descripcion_procedimiento": str(payload.get("descripcion_procedimiento") or ""),
                "diagnosticos": diagnostics,
                "procedimientos": procedures,
                "procedimientos_clasificados": classified_procedures,
                "ayudas_diagnosticas": _normalize_dict_list(payload.get("ayudas_diagnosticas")),
                "imagenes_diagnosticas": _normalize_text_list(payload.get("imagenes_diagnosticas")),
                "medicamentos": [formatear_medicamento_canonico(item) for item in medicamentos_detallados],
                "medicamentos_detallados": medicamentos_detallados,
                "notas_medicas": {
                    "hallazgos_extra": str(notas_medicas.get("hallazgos_extra") or ""),
                    "descripcion_procedimiento_extra": str(
                        notas_medicas.get("descripcion_procedimiento_extra") or ""
                    ),
                },
            }
        )

        return {
            "mensaje": "PDF de epicrisis almacenado",
            "cache_id": str(insert_result.inserted_id),
            "nombre_paciente": nombre_paciente,
            "case_key": case_key,
            "fecha_guardado": datetime.now().isoformat(),
        }
    except HTTPException:
        raise
    except Exception as exc:
        logger.warning("Error guardando cache PDF de epicrisis: %s", exc)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="No se pudo guardar el PDF de epicrisis"
        )


@router.get("/epicrisis/pdf_cache/print/{cache_id}", response_class=HTMLResponse)
async def imprimir_epicrisis_pdf_cache(
    cache_id: str,
    current_user: CurrentUser,
    services: ServicesDep,
):
    mongo = services.mongo_analyses
    try:
        if not ObjectId.is_valid(cache_id):
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="ID de cache no valido")

        cache_collection = _get_epicrisis_pdf_cache_collection(mongo)
        cache_doc = cache_collection.find_one({"_id": ObjectId(cache_id), "usuario": current_user.username})
        if not cache_doc:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND, detail="No se encontró el PDF almacenado"
            )

        html_pdf = str(cache_doc.get("html_pdf") or "").strip()
        if not html_pdf:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND, detail="El cache no contiene contenido imprimible"
            )

        return HTMLResponse(content=_inject_print_script(html_pdf))
    except HTTPException:
        raise
    except Exception as exc:
        logger.warning("Error cargando cache PDF de epicrisis: %s", exc)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="No se pudo cargar el PDF de epicrisis"
        )


@router.get("/epicrisis/pdf_cache/ultimo", response_class=HTMLResponse)
async def imprimir_ultimo_pdf_epicrisis_paciente(
    nombre_paciente: str = "",
    case_key: str = "",
    *,
    current_user: CurrentUser,
    services: ServicesDep,
):
    mongo = services.mongo_analyses
    try:
        cache_collection = _get_epicrisis_pdf_cache_collection(mongo)
        query = {"usuario": current_user.username}
        if case_key:
            query["case_key"] = case_key
        else:
            query["nombre_paciente"] = nombre_paciente
        cache_doc = cache_collection.find_one(query, sort=[("fecha_guardado", -1)])
        if not cache_doc:
            return HTMLResponse(
                status_code=status.HTTP_404_NOT_FOUND,
                content=(
                    "<html><head><meta charset='utf-8'><title>PDF no disponible</title></head>"
                    "<body style='font-family: Arial, sans-serif; padding: 24px;'>"
                    "<h2>No hay PDF de epicrisis guardado</h2>"
                    "<p>Primero genera el PDF desde la pagina de epicrisis para este paciente o caso.</p>"
                    "</body></html>"
                ),
            )

        html_pdf = str(cache_doc.get("html_pdf") or "").strip()
        if not html_pdf:
            return HTMLResponse(
                status_code=status.HTTP_404_NOT_FOUND,
                content=(
                    "<html><head><meta charset='utf-8'><title>PDF vacío</title></head>"
                    "<body style='font-family: Arial, sans-serif; padding: 24px;'>"
                    "<h2>El ultimo PDF guardado no tiene contenido imprimible</h2>"
                    "<p>Vuelve a generar el PDF desde la epicrisis e intenta nuevamente.</p>"
                    "</body></html>"
                ),
            )

        return HTMLResponse(content=_inject_print_script(html_pdf))
    except HTTPException:
        raise
    except Exception as exc:
        logger.warning("Error cargando último PDF de epicrisis por paciente: %s", exc)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="No se pudo cargar el PDF de epicrisis"
        )
