from __future__ import annotations

import json
from typing import Any

from app.llm import LLMOutputKind, LLMStructuredRequest, LLMTask
from app.llm.schemas import MedicationPertinenceReviewCollection


_PROMPT_VERSION = "v2"


class LLMMedicationPertinenceReviewer:
    def __init__(self, llm_router: Any) -> None:
        self.llm_router = llm_router

    def review(
        self,
        *,
        medications: list[dict[str, Any]],
        diagnoses: list[dict[str, Any]],
        procedures: list[dict[str, Any]],
    ) -> list[dict[str, Any]]:
        if self.llm_router is None or not medications:
            return []
        payload = {
            "medicamentos": [self._medication_payload(item) for item in medications],
            "diagnosticos": [self._clinical_item(item) for item in diagnoses[:20]],
            "procedimientos": [self._clinical_item(item) for item in procedures[:20]],
        }
        prompt = (
            "Evalúa la pertinencia clínica de cada medicamento para auditoría de cuentas médicas en Colombia. "
            "Conserva exactamente la clave k. Usa posible_glosa solo cuando exista una incoherencia clínica "
            "sustentada; incluye una justificación concreta y cita en ev únicamente identificadores eid "
            "del catálogo de evidencia del mismo medicamento. No copies ni inventes fragmentos de evidencia. "
            "Usa revisar si la evidencia es insuficiente. No rebajes riesgos documentales ya detectados.\n\n"
            f"Contexto estructurado:\n{json.dumps(payload, ensure_ascii=False)}"
        )
        try:
            response = self.llm_router.generate_structured(
                LLMStructuredRequest(
                    task=LLMTask.MEDICATION_PERTINENCE,
                    prompt=prompt,
                    output_model=MedicationPertinenceReviewCollection,
                    output_kind=LLMOutputKind.STRUCTURED_COLLECTION,
                    system_prompt=(
                        "Eres auditor médico. Responde solo JSON válido, no inventes evidencia y trata "
                        "cada resultado como recomendación revisable."
                    ),
                    metadata={
                        "operation": "medication_pertinence",
                        "prompt_version": _PROMPT_VERSION,
                    },
                )
            )
            model = MedicationPertinenceReviewCollection.model_validate(response.content)
        except Exception:
            return []
        return [item.model_dump(mode="json") for item in model.items]

    @staticmethod
    def _medication_payload(item: dict[str, Any]) -> dict[str, Any]:
        raw_pertinence = item.get("pertinencia")
        pertinence: dict[str, Any] = raw_pertinence if isinstance(raw_pertinence, dict) else {}
        return {
            "k": str(item.get("key") or ""),
            "nombre": str(item.get("nombre") or item.get("medicamento") or "")[:120],
            "dosis": str(item.get("dosis") or "")[:80],
            "posologia": str(item.get("posologia") or "")[:120],
            "estados": [str(value) for value in item.get("estados") or []],
            "cadena": pertinence.get("cadena") or {},
            "hallazgos_documentales": [str(value)[:240] for value in pertinence.get("motivos") or []],
            "evidence_catalog": [
                {
                    "eid": str(evidence.get("evidence_id") or ""),
                    "rol": str(evidence.get("role") or ""),
                    "fuente": str(evidence.get("fuente") or "")[:120],
                    "fragmento": str(evidence.get("evidencia") or "")[:240],
                }
                for evidence in item.get("evidencias") or []
                if isinstance(evidence, dict) and str(evidence.get("evidence_id") or "")
            ][:12],
        }

    @staticmethod
    def _clinical_item(item: dict[str, Any]) -> dict[str, str]:
        return {
            "codigo": str(item.get("codigo") or item.get("codigo_cups") or "")[:30],
            "descripcion": str(
                item.get("descripcion") or item.get("diagnostico") or item.get("procedimiento") or ""
            )[:240],
        }
