from __future__ import annotations

from importlib import import_module
from typing import Any, Final

from bson import ObjectId
from fastapi import APIRouter, HTTPException, Request
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
from pydantic import BaseModel, ConfigDict, Field
from starlette import status

from app.batch_processing.infrastructure.mongo_repositories import MongoBatchCaseRepository
from app.core.logging import get_audit_logger
from app.services.clinical_processing import extraer_nombre_paciente
from app.services.demo_identity_service import get_demo_identity_service

from .common import (
    AppServices,
    CurrentUser,
    ServicesDep,
    _apply_legacy_epicrisis_deprecation_headers,
    _build_epicrisis_blocking_detail,
    _build_epicrisis_document_bundle,
    _build_epicrisis_regen_url,
    _build_epicrisis_rule_diagnostic,
    _build_full_epicrisis_context,
    _cache_legacy_epicrisis_context,
    _canonical_case_epicrisis_url,
    _find_legacy_cached_epicrisis,
    _prepare_epicrisis_template_context,
    _render_epicrisis_status_view,
    _render_legacy_cached_epicrisis,
    _sanitize_epicrisis_error_detail,
    logger,
)


router = APIRouter()

EPICRISIS_TEMPLATE: Final[str] = "epicrisis.html"


class PdfPreparationMetadataPatch(BaseModel):
    model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)

    procedure_key: str = Field(min_length=1)
    group: int | None = Field(default=None, ge=2, le=23)


def _case_repo() -> MongoBatchCaseRepository:
    return MongoBatchCaseRepository()


def _find_latest_case_document_impl(mongo, username: str, case_key: str) -> dict | None:
    return mongo.collection.find_one(
        {
            "usuario": username,
            "case_key": case_key,
            "tipo_documento": {"$nin": ["epicrisis", "epicrisis_case_cache"]},
        },
        sort=[("fecha_analisis", -1)],
    )


def _find_latest_case_document(mongo, username: str, case_key: str) -> dict | None:
    pages_package = import_module("app.routes.pages")
    finder = getattr(pages_package, "_find_latest_case_document", _find_latest_case_document_impl)
    return finder(mongo, username, case_key)


def _epicrisis_queue_response(
    *,
    case_key: str,
    job_id: str,
    status_value: str,
    reused: bool,
    epicrisis_url: str | None = None,
) -> dict[str, object]:
    return {
        "job_id": job_id,
        "status": status_value,
        "reused": reused,
        "epicrisis_url": epicrisis_url or _canonical_case_epicrisis_url(case_key),
    }


def _case_cached_context(
    *,
    services: AppServices,
    username: str,
    case_key: str,
    regen: bool,
) -> dict[str, Any] | None:
    if regen:
        return None
    return services.case_epicrisis_service.get_cached_case_context(username, case_key)


def _has_cached_case_context(cached_context: dict[str, Any] | None) -> bool:
    return bool(cached_context and isinstance(cached_context.get("contexto"), dict))


def _queue_case_epicrisis_job(
    *,
    services: AppServices,
    username: str,
    case_key: str,
    regen: bool = False,
) -> dict[str, object]:
    try:
        return services.case_epicrisis_runtime_service.queue_case_epicrisis(
            username,
            case_key,
            regen=regen,
        )
    except ValueError as exc:
        detail = str(exc)
        if detail == "Caso no encontrado":
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=detail) from exc
        if detail == "El caso aún no esta listo para generar epicrisis.":
            raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=detail) from exc
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=detail) from exc


def _safe_get_case_epicrisis_status(
    services: AppServices,
    username: str,
    case_key: str,
) -> dict[str, Any] | None:
    try:
        return services.case_epicrisis_runtime_service.get_case_epicrisis_status(username, case_key)
    except ValueError:
        return None


def _resolve_real_case_key(*, services: AppServices, username: str, visible_case_key: str) -> str:
    return get_demo_identity_service(services).resolve_case_key(
        username=username,
        visible_case_key=str(visible_case_key or "").strip(),
    )


def _visible_case_identity(
    *,
    services: AppServices,
    username: str,
    case_key: str,
    case_number: str = "",
    patient_id: str = "",
    patient_name: str = "",
) -> dict[str, str]:
    return get_demo_identity_service(services).project_case_identity(
        username=username,
        case_key=case_key,
        case_number=case_number,
        patient_id=patient_id,
        patient_name=patient_name,
    )


def _resolve_case_number(
    *,
    case_key: str,
    case_status: dict[str, Any] | None,
    latest_case_doc: dict[str, Any] | None,
) -> str:
    return str(
        (case_status or {}).get("case_number") or (latest_case_doc or {}).get("case_number") or case_key
    )


def _render_case_epicrisis_blocked_view(
    *,
    request: Request,
    current_user: CurrentUser,
    templates,
    case_key: str,
    case_number: str,
    status_payload: dict[str, Any] | None,
) -> Any:
    rule_diagnostic = _build_epicrisis_rule_diagnostic(status_payload)
    return _render_epicrisis_status_view(
        request=request,
        templates=templates,
        current_user=current_user,
        status_variant="error",
        title="No fue posible generar la epicrisis",
        case_key=case_key,
        case_number=case_number,
        message="No se puede generar la epicrisis con la documentación actual.",
        detail=_build_epicrisis_blocking_detail(status_payload)
        or "Adjunta el soporte requerido y vuelve a intentar.",
        primary_action_href=_build_epicrisis_regen_url(case_key=case_key)
        or _canonical_case_epicrisis_url(case_key),
        primary_action_label="Volver a generar epicrisis",
        status_code=status.HTTP_409_CONFLICT,
        rule_diagnostic=rule_diagnostic,
    )


def _maybe_render_cached_case_epicrisis(
    *,
    request: Request,
    current_user: CurrentUser,
    services: AppServices,
    case_key: str,
    visible_case_key: str,
    regen: bool,
) -> Any | None:
    cache_doc = _case_cached_context(
        services=services,
        username=current_user.username,
        case_key=case_key,
        regen=regen,
    )
    if not _has_cached_case_context(cache_doc):
        return None
    if not isinstance(cache_doc, dict):
        return None
    context = cache_doc.get("contexto")
    if not isinstance(context, dict):
        return None

    visible_identity = _visible_case_identity(
        services=services,
        username=current_user.username,
        case_key=case_key,
        case_number=str(context.get("case_number") or ""),
        patient_id=str(context.get("patient_id") or ""),
        patient_name=str(context.get("patient_name") or context.get("nombre_paciente") or ""),
    )
    regen_url = _build_epicrisis_regen_url(case_key=visible_case_key)
    if not bool(context.get("epicrisis_generation_allowed", True)):
        return _render_case_epicrisis_blocked_view(
            request=request,
            current_user=current_user,
            templates=services.templates,
            case_key=visible_case_key,
            case_number=str(context.get("case_number") or visible_case_key),
            status_payload={
                "epicrisis_error": context.get("blocking_reason"),
                "epicrisis_blocking_reason": context.get("blocking_reason"),
                "epicrisis_missing_documents": context.get("missing_documents") or [],
                "epicrisis_rule_findings": ((context.get("rule_evaluation") or {}).get("findings") or []),
            },
        )

    prepared = _prepare_epicrisis_template_context(
        get_demo_identity_service(services).project_epicrisis_context(
            username=current_user.username,
            context=context,
            case_key=case_key,
            case_number=str(context.get("case_number") or ""),
            patient_id=str(context.get("patient_id") or ""),
            patient_name=str(context.get("patient_name") or context.get("nombre_paciente") or ""),
        ),
        request=request,
        current_user=current_user,
        regen_url=regen_url,
        regen_case_key=str(visible_identity.get("case_key") or visible_case_key),
        epicrisis_cached=True,
        cie10_retriever=services.cie10_retriever,
    )
    return services.templates.TemplateResponse(request, EPICRISIS_TEMPLATE, prepared)


def _maybe_render_failed_case_epicrisis(
    *,
    request: Request,
    current_user: CurrentUser,
    templates,
    case_key: str,
    case_number: str,
    case_status: dict[str, Any] | None,
    regen: bool,
) -> Any | None:
    current_status = str((case_status or {}).get("epicrisis_status") or "").strip().lower()
    if current_status != "fallido" or regen:
        return None

    is_blocked = str((case_status or {}).get("epicrisis_rule_status") or "").strip().lower() == "blocked"
    if is_blocked:
        return _render_case_epicrisis_blocked_view(
            request=request,
            current_user=current_user,
            templates=templates,
            case_key=case_key,
            case_number=case_number,
            status_payload=case_status,
        )
    return _render_epicrisis_status_view(
        request=request,
        templates=templates,
        current_user=current_user,
        status_variant="error",
        title="No fue posible generar la epicrisis",
        case_key=case_key,
        case_number=case_number,
        message="Ocurrió un error al generar la epicrisis.",
        detail=_sanitize_epicrisis_error_detail((case_status or {}).get("epicrisis_error"))
        or "Puedes volver a intentarlo desde esta misma pantalla.",
        primary_action_href=_build_epicrisis_regen_url(case_key=case_key)
        or _canonical_case_epicrisis_url(case_key),
        primary_action_label="Volver a generar epicrisis",
        status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
    )


def _render_case_queue_result(
    *,
    request: Request,
    current_user: CurrentUser,
    services: AppServices,
    case_key: str,
    visible_case_key: str,
    case_number: str,
    case_status: dict[str, Any] | None,
    queue_result: dict[str, object],
) -> Any:
    regen_url = _build_epicrisis_regen_url(case_key=visible_case_key) or _canonical_case_epicrisis_url(
        visible_case_key
    )
    queued_status = str(
        queue_result.get("status") or (case_status or {}).get("epicrisis_status") or "en_cola"
    )
    if queued_status == "fallido":
        refreshed_status = services.case_epicrisis_runtime_service.get_case_epicrisis_status(
            current_user.username,
            case_key,
        )
        return _render_case_epicrisis_blocked_view(
            request=request,
            current_user=current_user,
            templates=services.templates,
            case_key=visible_case_key,
            case_number=case_number,
            status_payload=refreshed_status,
        )

    if queued_status == "completado":
        refreshed_cache = services.case_epicrisis_service.get_cached_case_context(
            current_user.username, case_key
        )
        refreshed_context = refreshed_cache.get("contexto") if isinstance(refreshed_cache, dict) else None
        if isinstance(refreshed_context, dict):
            context = _prepare_epicrisis_template_context(
                get_demo_identity_service(services).project_epicrisis_context(
                    username=current_user.username,
                    context=refreshed_context,
                    case_key=case_key,
                    case_number=str(refreshed_context.get("case_number") or case_number),
                    patient_id=str(refreshed_context.get("patient_id") or ""),
                    patient_name=str(
                        refreshed_context.get("patient_name") or refreshed_context.get("nombre_paciente") or ""
                    ),
                ),
                request=request,
                current_user=current_user,
                regen_url=regen_url,
                regen_case_key=visible_case_key,
                epicrisis_cached=True,
                cie10_retriever=services.cie10_retriever,
            )
            return services.templates.TemplateResponse(request, EPICRISIS_TEMPLATE, context)

    return _render_epicrisis_status_view(
        request=request,
        templates=services.templates,
        current_user=current_user,
        status_variant="processing",
        title="Epicrisis del caso en preparación",
        case_key=visible_case_key,
        case_number=case_number,
        message="Estamos preparando la epicrisis. Actualiza en unos segundos o vuelve más tarde.",
        detail=f"Estado actual: {queued_status}",
        primary_action_href=_canonical_case_epicrisis_url(visible_case_key),
        primary_action_label="Recargar",
        status_code=status.HTTP_202_ACCEPTED,
    )


def _load_legacy_base_document(mongo, *, document_id: str, username: str) -> dict[str, Any]:
    if not ObjectId.is_valid(document_id):
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="ID no válido")

    base_doc = mongo.collection.find_one({"_id": ObjectId(document_id)})
    if not base_doc or base_doc.get("usuario") != username:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Documento no encontrado o acceso denegado",
        )
    return base_doc


def _maybe_redirect_legacy_epicrisis(
    *,
    base_doc: dict[str, Any],
    services: AppServices,
    username: str,
    regen: bool,
) -> Any | None:
    base_case_key = str(base_doc.get("case_key") or "").strip()
    if not base_case_key:
        return None
    visible_case_key = _visible_case_identity(
        services=services,
        username=username,
        case_key=base_case_key,
        case_number=str(base_doc.get("case_number") or ""),
        patient_id=str(base_doc.get("patient_id") or ""),
        patient_name=str(base_doc.get("nombre_paciente") or ""),
    ).get("case_key", base_case_key)
    return _apply_legacy_epicrisis_deprecation_headers(
        RedirectResponse(
            url=f"{_canonical_case_epicrisis_url(visible_case_key)}{'&regen=1' if regen else ''}",
            status_code=status.HTTP_307_TEMPORARY_REDIRECT,
        )
    )


def _render_epicrisis_unexpected_error(
    *,
    request: Request,
    current_user: CurrentUser,
    templates,
    normalized_case_key: str,
    resolved_document_id: str,
    base_doc: dict[str, Any] | None,
    latest_case_doc: dict[str, Any] | None,
) -> Any:
    if normalized_case_key or resolved_document_id:
        case_number = str(
            (base_doc or {}).get("case_number")
            or (latest_case_doc or {}).get("case_number")
            or normalized_case_key
            or resolved_document_id
        )
        return _render_epicrisis_status_view(
            request=request,
            templates=templates,
            current_user=current_user,
            status_variant="error",
            title="No fue posible generar la epicrisis",
            case_key=normalized_case_key,
            case_number=case_number,
            message="Ocurrió un error al generar la epicrisis.",
            detail="Intenta nuevamente. Si el problema persiste, revisa los documentos asociados al caso.",
            primary_action_href=(
                _build_epicrisis_regen_url(
                    case_key=normalized_case_key,
                    documento_id=resolved_document_id or None,
                )
                or request.url.path
            ),
            primary_action_label="Volver a generar epicrisis",
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
        )
    raise HTTPException(
        status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
        detail="Error al generar la epicrisis",
    )


def _handle_case_key_epicrisis_view(
    *,
    request: Request,
    current_user: CurrentUser,
    services: AppServices,
    case_key: str,
    visible_case_key: str,
    regen: bool,
) -> Any:
    latest_case_doc = _find_latest_case_document(services.mongo_analyses, current_user.username, case_key)
    cached_response = _maybe_render_cached_case_epicrisis(
        request=request,
        current_user=current_user,
        services=services,
        case_key=case_key,
        visible_case_key=visible_case_key,
        regen=regen,
    )
    if cached_response is not None:
        return cached_response

    case_status = _safe_get_case_epicrisis_status(services, current_user.username, case_key)
    if not case_status and not latest_case_doc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Caso no encontrado")

    case_number = _resolve_case_number(
        case_key=case_key, case_status=case_status, latest_case_doc=latest_case_doc
    )
    failed_response = _maybe_render_failed_case_epicrisis(
        request=request,
        current_user=current_user,
        templates=services.templates,
        case_key=visible_case_key,
        case_number=case_number,
        case_status=case_status,
        regen=regen,
    )
    if failed_response is not None:
        return failed_response

    try:
        queue_result = _queue_case_epicrisis_job(
            services=services,
            username=current_user.username,
            case_key=case_key,
            regen=regen,
        )
    except HTTPException as exc:
        if exc.status_code == status.HTTP_409_CONFLICT:
            refreshed_status = _safe_get_case_epicrisis_status(services, current_user.username, case_key)
            status_payload = refreshed_status or {
                "epicrisis_error": exc.detail,
                "epicrisis_blocking_reason": exc.detail,
            }
            return _render_case_epicrisis_blocked_view(
                request=request,
                current_user=current_user,
                templates=services.templates,
                case_key=visible_case_key,
                case_number=case_number,
                status_payload=status_payload,
            )
        raise
    except Exception:
        logger.exception("Error encolando/generando epicrisis case-aware")
        return _render_epicrisis_status_view(
            request=request,
            templates=services.templates,
            current_user=current_user,
            status_variant="error",
            title="No fue posible generar la epicrisis",
            case_key=visible_case_key,
            case_number=case_number,
            message="Ocurrió un error al generar la epicrisis.",
            detail="Intenta nuevamente. Si el problema persiste, revisa los documentos asociados al caso.",
            primary_action_href=_build_epicrisis_regen_url(case_key=visible_case_key)
            or _canonical_case_epicrisis_url(visible_case_key),
            primary_action_label="Volver a generar epicrisis",
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
        )

    return _render_case_queue_result(
        request=request,
        current_user=current_user,
        services=services,
        case_key=case_key,
        visible_case_key=visible_case_key,
        case_number=case_number,
        case_status=case_status,
        queue_result=queue_result,
    )


def _handle_legacy_epicrisis_view(
    *,
    request: Request,
    current_user: CurrentUser,
    services: AppServices,
    resolved_document_id: str,
    regen: bool,
) -> Any:
    base_doc = _load_legacy_base_document(
        services.mongo_analyses,
        document_id=resolved_document_id,
        username=current_user.username,
    )
    redirect_response = _maybe_redirect_legacy_epicrisis(
        base_doc=base_doc,
        services=services,
        username=current_user.username,
        regen=regen,
    )
    if redirect_response is not None:
        return redirect_response

    nombre_paciente = str(base_doc.get("nombre_paciente") or "").strip() or extraer_nombre_paciente(base_doc)
    bundle = _build_epicrisis_document_bundle(
        services.mongo_analyses,
        current_user.username,
        nombre_paciente,
        base_doc=base_doc,
    )
    regen_url = _build_epicrisis_regen_url(
        case_key=_visible_case_identity(
            services=services,
            username=current_user.username,
            case_key=str(base_doc.get("case_key") or "").strip(),
            case_number=str(base_doc.get("case_number") or ""),
            patient_id=str(base_doc.get("patient_id") or ""),
            patient_name=nombre_paciente,
        ).get("case_key", str(base_doc.get("case_key") or "").strip()),
        documento_id=resolved_document_id,
    )

    if not regen:
        cache_doc = _find_legacy_cached_epicrisis(
            services.mongo_analyses,
            username=current_user.username,
            resolved_document_id=resolved_document_id,
            bundle=bundle,
        )
        if cache_doc and isinstance(cache_doc.get("contexto"), dict):
            return _render_legacy_cached_epicrisis(
                request=request,
                current_user=current_user,
                templates=services.templates,
                cie10_retriever=services.cie10_retriever,
                cache_doc=cache_doc,
                bundle=bundle,
                regen_url=regen_url,
                services=services,
            )

    context = _build_full_epicrisis_context(
        services=services,
        bundle=bundle,
        username=current_user.username,
        cie10_retriever=services.cie10_retriever,
        regen_url=regen_url,
        regen_case_key="",
        epicrisis_cached=False,
        request=request,
        current_user=current_user,
    )
    projected_context = get_demo_identity_service(services).project_epicrisis_context(
        username=current_user.username,
        context=context,
        case_key=str(base_doc.get("case_key") or "").strip(),
        case_number=str(base_doc.get("case_number") or ""),
        patient_id=str(base_doc.get("patient_id") or ""),
        patient_name=nombre_paciente,
    )
    _cache_legacy_epicrisis_context(
        services.mongo_analyses,
        username=current_user.username,
        resolved_document_id=resolved_document_id,
        bundle=bundle,
        contexto=context,
        regen=regen,
    )
    return _apply_legacy_epicrisis_deprecation_headers(
        services.templates.TemplateResponse(request, EPICRISIS_TEMPLATE, projected_context)
    )


@router.get("/epicrisis", response_class=HTMLResponse)
async def epicrisis_view(
    request: Request,
    id: str | None = None,
    documento_id: str | None = None,
    case_key: str | None = None,
    regen: bool = False,
    *,
    current_user: CurrentUser,
    services: ServicesDep,
):
    templates = services.templates
    normalized_case_key = ""
    resolved_document_id = ""
    base_doc: dict[str, Any] | None = None
    latest_case_doc: dict[str, Any] | None = None
    try:
        normalized_case_key = str(case_key or "").strip()
        if normalized_case_key:
            real_case_key = _resolve_real_case_key(
                services=services,
                username=current_user.username,
                visible_case_key=normalized_case_key,
            )
            latest_case_doc = _find_latest_case_document(
                services.mongo_analyses,
                current_user.username,
                real_case_key,
            )
            return _handle_case_key_epicrisis_view(
                request=request,
                current_user=current_user,
                services=services,
                case_key=real_case_key,
                visible_case_key=normalized_case_key,
                regen=regen,
            )

        resolved_document_id = str(documento_id or id or "").strip()
        if not resolved_document_id:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Debes indicar 'case_key' o 'documento_id' para cargar la epicrisis.",
            )
        return _handle_legacy_epicrisis_view(
            request=request,
            current_user=current_user,
            services=services,
            resolved_document_id=resolved_document_id,
            regen=regen,
        )
    except HTTPException:
        raise
    except Exception as exc:
        logger.exception("Error en epicrisis_view")
        get_audit_logger().business_event(
            event_type="epicrisis.view_failed",
            action="render_epicrisis_view",
            outcome="error",
            service="routes_pages_epicrisis",
            error={"class": exc.__class__.__name__},
        )
        return _render_epicrisis_unexpected_error(
            request=request,
            current_user=current_user,
            templates=templates,
            normalized_case_key=normalized_case_key,
            resolved_document_id=resolved_document_id,
            base_doc=base_doc,
            latest_case_doc=latest_case_doc,
        )


@router.get("/epicrisis/caso/{case_key}", response_class=HTMLResponse)
async def epicrisis_case_view(
    case_key: str,
    current_user: CurrentUser,
    services: ServicesDep,
):
    real_case_key = _resolve_real_case_key(
        services=services,
        username=current_user.username,
        visible_case_key=case_key,
    )
    case = _case_repo().get_user_case(current_user.username, real_case_key)
    if not case:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Caso no encontrado")
    return RedirectResponse(
        url=_canonical_case_epicrisis_url(case_key), status_code=status.HTTP_307_TEMPORARY_REDIRECT
    )


@router.post("/epicrisis")
async def solicitar_epicrisis_case_aware(
    case_key: str = "",
    regen: bool = False,
    *,
    current_user: CurrentUser,
    services: ServicesDep,
):
    normalized_case_key = str(case_key or "").strip()
    if not normalized_case_key:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="El parámetro 'case_key' es obligatorio.",
        )

    real_case_key = _resolve_real_case_key(
        services=services,
        username=current_user.username,
        visible_case_key=normalized_case_key,
    )
    queue_result = _queue_case_epicrisis_job(
        services=services,
        username=current_user.username,
        case_key=real_case_key,
        regen=regen,
    )
    status_data = services.case_epicrisis_runtime_service.get_case_epicrisis_status(
        current_user.username,
        real_case_key,
    )
    visible_identity = _visible_case_identity(
        services=services,
        username=current_user.username,
        case_key=real_case_key,
        case_number=str(status_data.get("case_number") or ""),
        patient_id=str(status_data.get("patient_id") or ""),
        patient_name=str(status_data.get("patient_name") or ""),
    )
    current_status = str(queue_result.get("status") or status_data.get("epicrisis_status") or "en_cola")
    STATUS_CODE_MAPPING = {
        "completado": status.HTTP_200_OK,
        "fallido": status.HTTP_409_CONFLICT,
        "en_cola": status.HTTP_202_ACCEPTED
    }
    return JSONResponse(
        status_code=STATUS_CODE_MAPPING.get(current_status, status.HTTP_202_ACCEPTED),
        content={
            "case_key": visible_identity.get("case_key", normalized_case_key),
            "case_number": status_data.get("case_number", ""),
            "epicrisis_status": current_status,
            "epicrisis_job_id": queue_result.get("job_id", status_data.get("epicrisis_job_id", "")),
            "epicrisis_url": _canonical_case_epicrisis_url(visible_identity.get("case_key", normalized_case_key)),
            "reused": bool(queue_result.get("reused", False)),
            "ready_for_epicrisis": bool(status_data.get("ready_for_epicrisis", False)),
            "epicrisis_rule_status": status_data.get("epicrisis_rule_status", ""),
            "epicrisis_rule_findings": status_data.get("epicrisis_rule_findings", []),
            "epicrisis_blocking_reason": status_data.get("epicrisis_blocking_reason", ""),
            "epicrisis_missing_documents": status_data.get("epicrisis_missing_documents", []),
        },
    )


@router.get("/epicrisis/estado")
async def estado_epicrisis_case_aware(
    case_key: str = "",
    *,
    current_user: CurrentUser,
    services: ServicesDep,
):
    normalized_case_key = str(case_key or "").strip()
    if not normalized_case_key:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="El parámetro 'case_key' es obligatorio.",
        )

    real_case_key = _resolve_real_case_key(
        services=services,
        username=current_user.username,
        visible_case_key=normalized_case_key,
    )
    try:
        payload = services.case_epicrisis_runtime_service.get_case_epicrisis_status(
            current_user.username,
            real_case_key,
        )
        visible_identity = _visible_case_identity(
            services=services,
            username=current_user.username,
            case_key=real_case_key,
            case_number=str(payload.get("case_number") or ""),
            patient_id=str(payload.get("patient_id") or ""),
            patient_name=str(payload.get("patient_name") or ""),
        )
        if isinstance(payload, dict):
            payload = {
                **payload,
                "case_key": visible_identity.get("case_key", normalized_case_key),
                "epicrisis_url": _canonical_case_epicrisis_url(visible_identity.get("case_key", normalized_case_key)),
            }
        return payload
    except ValueError as exc:
        detail = str(exc)
        if detail == "Caso no encontrado":
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=detail) from exc
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=detail) from exc


@router.patch("/api/epicrisis/cases/{case_key}/draft")
async def actualizar_draft_epicrisis_case_aware(
    case_key: str,
    request: Request,
    current_user: CurrentUser,
    services: ServicesDep,
):
    normalized_case_key = str(case_key or "").strip()
    if not normalized_case_key:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="El parámetro 'case_key' es obligatorio.",
        )

    real_case_key = _resolve_real_case_key(
        services=services,
        username=current_user.username,
        visible_case_key=normalized_case_key,
    )
    payload = await request.json()
    if not isinstance(payload, dict):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Payload invalido.",
        )

    context = services.case_epicrisis_service.update_case_draft(
        current_user.username,
        real_case_key,
        payload=payload,
    )
    return {
        "case_key": _visible_case_identity(
            services=services,
            username=current_user.username,
            case_key=real_case_key,
        ).get("case_key", normalized_case_key),
        "manual_soat_results": context.get("manual_soat_results", []),
        "pdf_draft": context.get("pdf_draft", {}),
        "codigos_desde_soat": context.get("codigos_desde_soat", []),
        "diagnosticos_consolidados": context.get("diagnosticos_consolidados", []),
        "diagnosticos_pendientes_validacion": context.get("diagnosticos_pendientes_validacion", []),
        "diagnosticos_consolidacion_hallazgos": context.get("diagnosticos_consolidacion_hallazgos", []),
        "ayudas_diagnosticas": context.get("ayudas_diagnosticas", []),
        "imagenes_diagnosticas": context.get("imagenes_diagnosticas", []),
        "pdf_selectable_procedimientos": context.get("pdf_selectable_procedimientos", []),
    }


@router.patch("/api/epicrisis/cases/{case_key}/preparation-metadata")
async def actualizar_metadatos_preparacion_epicrisis(
    case_key: str,
    payload: PdfPreparationMetadataPatch,
    current_user: CurrentUser,
    services: ServicesDep,
):
    real_case_key = _resolve_real_case_key(
        services=services,
        username=current_user.username,
        visible_case_key=case_key,
    )
    try:
        context = services.case_epicrisis_service.update_pdf_preparation_metadata(
            current_user.username,
            real_case_key,
            procedure_key=payload.procedure_key,
            group=payload.group,
        )
    except LookupError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
    except ValueError as exc:
        raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=str(exc)) from exc
    return {
        "case_key": case_key,
        "pdf_preparation_user_metadata": context.get("pdf_preparation_user_metadata", {}),
        "pdf_preparation_procedimientos": context.get("pdf_preparation_procedimientos", []),
    }


@router.get("/api/epicrisis/cases/{case_key}/curation")
async def obtener_curacion_epicrisis(
    case_key: str,
    current_user: CurrentUser,
    services: ServicesDep,
):
    real_case_key = _resolve_real_case_key(
        services=services,
        username=current_user.username,
        visible_case_key=case_key,
    )
    payload = services.case_epicrisis_service.get_case_curation(
        current_user.username,
        real_case_key,
    )
    return {"case_key": case_key, **payload}


@router.patch("/api/epicrisis/cases/{case_key}/curation/items/{item_id}")
async def actualizar_item_curacion_epicrisis(
    case_key: str,
    item_id: str,
    request: Request,
    current_user: CurrentUser,
    services: ServicesDep,
):
    payload = await request.json()
    if not isinstance(payload, dict):
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Payload inválido.")
    real_case_key = _resolve_real_case_key(
        services=services,
        username=current_user.username,
        visible_case_key=case_key,
    )
    try:
        manual_group_raw = payload.get("manual_surgical_group")
        manual_group = int(manual_group_raw) if str(manual_group_raw or "").strip() else None
        reference_year_raw = payload.get("reference_year")
        reference_year = int(reference_year_raw) if str(reference_year_raw or "").strip() else 2026
        selected_components = payload.get("selected_components")
        if not isinstance(selected_components, list):
            selected_components = []
        updated = services.case_epicrisis_service.update_case_curation_item(
            current_user.username,
            real_case_key,
            item_id=item_id,
            decision=str(payload.get("decision") or ""),
            expected_version=str(payload.get("expected_version") or ""),
            corrected_code=str(payload.get("corrected_code") or ""),
            corrected_description=str(payload.get("corrected_description") or ""),
            reason=str(payload.get("reason") or ""),
            selected_soat_code=str(payload.get("selected_soat_code") or ""),
            calculate_reference=payload.get("calculate_reference") is True,
            manual_soat_code=str(payload.get("manual_soat_code") or ""),
            manual_surgical_group=manual_group,
            selected_components=[str(item) for item in selected_components],
            reference_year=reference_year,
        )
    except LookupError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
    except ValueError as exc:
        detail = str(exc)
        response_status = (
            status.HTTP_409_CONFLICT
            if "recarga el caso" in detail
            else status.HTTP_422_UNPROCESSABLE_CONTENT
        )
        raise HTTPException(status_code=response_status, detail=detail) from exc
    return {"case_key": case_key, "curation": updated}
