from __future__ import annotations

import hashlib
import re
from collections.abc import Iterable
from dataclasses import dataclass
from enum import StrEnum
from typing import Any

from app.clinical_pipeline.domain.medications import (
    MedicationEvidenceRole,
    MedicationInvoiceAssociationStatus,
    MedicationPertinenceAssessment,
    MedicationPertinenceStatus,
    MedicationQuantityComparison,
    MedicationQuantityComparisonStatus,
    MedicationSupportChain,
    MedicationSupportEvidence,
    MedicationSupportState,
)
from app.services.historia_medicamentos import normalize_medication_key, parse_numeric_quantity


MEDICATION_PERTINENCE_VERSION = "v2"


class MedicationInvoiceState(StrEnum):
    AUSENTE = "ausente"
    INSUFICIENTE = "insuficiente"
    VALIDA = "valida"


_DISCHARGE_PATTERN = re.compile(
    r"\b(?:egreso|alta|ambulatori[oa]|domiciliari[oa]|por\s+\d+\s+d[ií]as?)\b",
    re.IGNORECASE,
)
_POSITIVE_ADMINISTRATION_PATTERN = re.compile(
    r"\b(?:administr(?:ó|ado|ada)|suministr(?:ó|ado|ada)|aplic(?:ó|ado|ada)|"
    r"infundi(?:ó|do|da)|recibi(?:ó|do|da)|emple(?:ó|ado|ada)|utiliz(?:ó|ado|ada))\b",
    re.IGNORECASE,
)
_EXCLUDED_CONTEXT_PATTERN = re.compile(
    r"\b(?:alerg(?:ia|ico|ica)|antecedente|medicamento habitual|niega|no\s+(?:recibi|se\s+administr)|"
    r"recomienda|orden(?:a|ado|ada)|prescri(?:be|to|ta)|suspende|pendiente|sin\s+administrar)\b",
    re.IGNORECASE,
)
_NON_ADMINISTRATION_DOCUMENT_TYPES = {"radiologia", "laboratorio"}
_UNIT_ALIASES = {
    "ampolla": "unidad",
    "ampollas": "unidad",
    "capsula": "unidad",
    "capsulas": "unidad",
    "frasco": "unidad",
    "frascos": "unidad",
    "tableta": "unidad",
    "tabletas": "unidad",
    "unidad": "unidad",
    "unidades": "unidad",
    "vial": "unidad",
    "viales": "unidad",
}


@dataclass(frozen=True, slots=True)
class _ContextualAdministration:
    found: bool
    sources: list[str]
    evidence: list[dict[str, Any]]


@dataclass(frozen=True, slots=True)
class _MedicationEvaluationContext:
    item: dict[str, Any]
    invoice_state: MedicationInvoiceState
    ordered: bool
    administered: bool
    billed: bool
    antecedent: bool
    discharge: bool
    association: MedicationInvoiceAssociationStatus
    sources: list[str]
    evidence: list[str]
    support_ids: MedicationSupportEvidence
    quantity_comparison: MedicationQuantityComparison


def _clean(value: Any) -> str:
    return re.sub(r"\s+", " ", str(value or "")).strip()


def _unique(values: Iterable[str]) -> list[str]:
    seen: set[str] = set()
    result: list[str] = []
    for raw in values:
        value = _clean(raw)
        key = value.casefold()
        if not value or key in seen:
            continue
        seen.add(key)
        result.append(value)
    return result


def _normalized_unit(value: Any) -> str:
    unit = normalize_medication_key(value)
    return _UNIT_ALIASES.get(unit, unit)


def _evidence_texts(item: dict[str, Any]) -> list[str]:
    return _unique(
        evidence.get("evidencia")
        for evidence in item.get("evidencias") or []
        if isinstance(evidence, dict)
    )


def _is_discharge_medication(item: dict[str, Any]) -> bool:
    statuses = {str(value).strip().lower() for value in item.get("estados") or []}
    if "formulado" not in statuses or "administrado" in statuses:
        return False
    sources = " ".join(str(value) for value in item.get("fuentes") or [])
    if "prescripcion" in normalize_medication_key(sources):
        return True
    context = [_clean(item.get("posologia")), *_evidence_texts(item)]
    return any(_DISCHARGE_PATTERN.search(text) for text in context)


def _document_type(source: Any) -> str:
    return normalize_medication_key(str(source or "").partition(":")[0]).replace(" ", "_")


def _evidence_identifier(source: str, medication_key: str, snippet: str) -> str:
    material = "|".join(
        (
            normalize_medication_key(source),
            medication_key,
            normalize_medication_key(snippet),
        )
    )
    return f"medev-{hashlib.sha256(material.encode('utf-8')).hexdigest()[:16]}"


def _medication_phrases(item: dict[str, Any]) -> list[str]:
    name = normalize_medication_key(item.get("nombre") or item.get("medicamento"))
    generic = normalize_medication_key(re.sub(r"\([^)]*\)", "", str(item.get("nombre") or "")))
    return sorted(
        {value for value in (name, generic) if value and len(value) >= 4},
        key=len,
        reverse=True,
    )


def _contextual_administration(
    item: dict[str, Any],
    support_documents: Iterable[dict[str, str]],
) -> _ContextualAdministration:
    phrases = _medication_phrases(item)
    if not phrases:
        return _ContextualAdministration(False, [], [])
    sources: list[str] = []
    evidence: list[dict[str, Any]] = []
    for document in support_documents:
        source = _clean(document.get("fuente")) or "soporte_asistencial"
        if _document_type(source) in _NON_ADMINISTRATION_DOCUMENT_TYPES:
            continue
        text = str(document.get("texto") or "")
        for segment in re.split(r"(?<=[.!?;])\s+|\n+", text):
            snippet = _clean(segment)
            normalized = normalize_medication_key(snippet)
            if not snippet or not any(phrase in normalized for phrase in phrases):
                continue
            if not _POSITIVE_ADMINISTRATION_PATTERN.search(snippet):
                continue
            if _EXCLUDED_CONTEXT_PATTERN.search(snippet):
                continue
            evidence.append(
                {
                    "evidence_id": _evidence_identifier(
                        source,
                        str(item.get("key") or ""),
                        snippet,
                    ),
                    "fuente": source,
                    "estado": "administrado",
                    "document_type": _document_type(source),
                    "document_name": _clean(source.partition(":")[2]),
                    "role": MedicationEvidenceRole.ADMINISTRACION.value,
                    "cantidad": None,
                    "unidad": "",
                    "evidencia": snippet[:240],
                }
            )
            sources.append(source)
            break
    return _ContextualAdministration(bool(evidence), _unique(sources), evidence)


def _support_ids(item: dict[str, Any]) -> MedicationSupportEvidence:
    grouped: dict[str, list[str]] = {
        MedicationEvidenceRole.ORDEN.value: [],
        MedicationEvidenceRole.ADMINISTRACION.value: [],
        MedicationEvidenceRole.FACTURACION.value: [],
    }
    for evidence in item.get("evidencias") or []:
        if not isinstance(evidence, dict):
            continue
        role = str(evidence.get("role") or "")
        evidence_id = _clean(evidence.get("evidence_id"))
        if role in grouped and evidence_id:
            grouped[role].append(evidence_id)
    return MedicationSupportEvidence(
        orden=_unique(grouped[MedicationEvidenceRole.ORDEN.value]),
        administracion=_unique(grouped[MedicationEvidenceRole.ADMINISTRACION.value]),
        facturacion=_unique(grouped[MedicationEvidenceRole.FACTURACION.value]),
    )


def _evidence_quantity(item: dict[str, Any], role: MedicationEvidenceRole) -> tuple[int | float | None, str]:
    quantities: list[int | float] = []
    units: set[str] = set()
    for evidence in item.get("evidencias") or []:
        if not isinstance(evidence, dict) or str(evidence.get("role") or "") != role.value:
            continue
        quantity = parse_numeric_quantity(evidence.get("cantidad"))
        if quantity is None:
            continue
        quantities.append(quantity)
        unit = _normalized_unit(evidence.get("unidad"))
        if unit:
            units.add(unit)
    if not quantities or len(units) > 1:
        return None, ""
    return sum(quantities), next(iter(units), "")


def _quantity_comparison(
    item: dict[str, Any],
    *,
    association: MedicationInvoiceAssociationStatus,
    billed: bool,
) -> MedicationQuantityComparison:
    if not billed:
        return MedicationQuantityComparison(estado=MedicationQuantityComparisonStatus.NO_APLICA)
    if association == MedicationInvoiceAssociationStatus.AMBIGUA:
        return MedicationQuantityComparison(
            estado=MedicationQuantityComparisonStatus.AMBIGUA,
            motivo="La línea facturada tiene más de un esquema clínico candidato.",
        )

    clinical_quantity, clinical_unit = _evidence_quantity(
        item,
        MedicationEvidenceRole.ADMINISTRACION,
    )
    billed_quantity = parse_numeric_quantity(item.get("cantidad_facturada"))
    _, billed_unit = _evidence_quantity(item, MedicationEvidenceRole.FACTURACION)
    billed_unit = billed_unit or _normalized_unit(item.get("unidad_cantidad"))
    if clinical_quantity is None or billed_quantity is None:
        return MedicationQuantityComparison(
            estado=MedicationQuantityComparisonStatus.NO_EVALUABLE,
            cantidad_clinica=clinical_quantity,
            unidad_clinica=clinical_unit,
            cantidad_facturada=billed_quantity,
            unidad_facturada=billed_unit,
            motivo="No hay cantidades de administración y facturación suficientes para comparar.",
        )
    if not clinical_unit or not billed_unit or clinical_unit != billed_unit:
        return MedicationQuantityComparison(
            estado=MedicationQuantityComparisonStatus.AMBIGUA,
            cantidad_clinica=clinical_quantity,
            unidad_clinica=clinical_unit,
            cantidad_facturada=billed_quantity,
            unidad_facturada=billed_unit,
            motivo="Las cantidades no tienen unidades equivalentes y requieren conciliación.",
        )
    return MedicationQuantityComparison(
        estado=MedicationQuantityComparisonStatus.COMPARABLE,
        cantidad_clinica=clinical_quantity,
        unidad_clinica=clinical_unit,
        cantidad_facturada=billed_quantity,
        unidad_facturada=billed_unit,
        motivo="Cantidades de administración y facturación expresadas en unidades equivalentes.",
    )


def _resolve_invoice_state(
    *,
    invoice_available: bool | None,
    invoice_state: MedicationInvoiceState | str | None,
) -> MedicationInvoiceState:
    if invoice_state is not None:
        return MedicationInvoiceState(str(invoice_state))
    return MedicationInvoiceState.VALIDA if invoice_available else MedicationInvoiceState.AUSENTE


def _association_status(item: dict[str, Any]) -> MedicationInvoiceAssociationStatus:
    try:
        return MedicationInvoiceAssociationStatus(
            str(item.get("asociacion_factura") or "no_evaluable")
        )
    except ValueError:
        return MedicationInvoiceAssociationStatus.NO_EVALUABLE


def _build_evaluation_context(
    item: dict[str, Any],
    *,
    invoice_state: MedicationInvoiceState,
    support_documents: Iterable[dict[str, str]],
) -> _MedicationEvaluationContext:
    statuses = {str(value).strip().lower() for value in item.get("estados") or []}
    contextual = _contextual_administration(item, support_documents)
    if contextual.evidence:
        item["evidencias"] = [*item.get("evidencias", []), *contextual.evidence]
    association = _association_status(item)
    billed = "facturado" in statuses
    if (
        invoice_state == MedicationInvoiceState.VALIDA
        and not billed
        and association == MedicationInvoiceAssociationStatus.NO_EVALUABLE
    ):
        association = MedicationInvoiceAssociationStatus.SIN_COINCIDENCIA
        item["asociacion_factura"] = association.value
    comparison = _quantity_comparison(item, association=association, billed=billed)
    return _MedicationEvaluationContext(
        item=item,
        invoice_state=invoice_state,
        ordered=bool(statuses & {"ordenado", "formulado"}),
        administered="administrado" in statuses or contextual.found,
        billed=billed,
        antecedent="antecedente" in statuses,
        discharge=_is_discharge_medication(item),
        association=association,
        sources=_unique([*item.get("fuentes", []), *contextual.sources]),
        evidence=_evidence_texts(item)[:4],
        support_ids=_support_ids(item),
        quantity_comparison=comparison,
    )


def _assessment(
    context: _MedicationEvaluationContext,
    *,
    status: MedicationPertinenceStatus,
    chain: MedicationSupportChain,
    reasons: list[str],
    rules: list[str],
) -> MedicationPertinenceAssessment:
    return MedicationPertinenceAssessment(
        estado=status,
        cadena=chain,
        soportes=context.support_ids,
        comparacion_cantidad=context.quantity_comparison,
        motivos=reasons,
        codigos_regla=rules,
        fuentes=context.sources,
        evidencias=context.evidence,
        version=MEDICATION_PERTINENCE_VERSION,
    )


def _antecedent_assessment(context: _MedicationEvaluationContext) -> MedicationPertinenceAssessment:
    return _assessment(
        context,
        status=MedicationPertinenceStatus.PERTINENTE,
        chain=MedicationSupportChain(
            orden=MedicationSupportState.NO_APLICA,
            administracion=MedicationSupportState.NO_APLICA,
            facturacion=MedicationSupportState.NO_APLICA,
        ),
        reasons=["Antecedente farmacológico; no requiere conciliación administrativa del caso."],
        rules=["MED-CTX-ANTECEDENTE"],
    )


def _discharge_assessment(context: _MedicationEvaluationContext) -> MedicationPertinenceAssessment:
    supported = context.ordered
    return _assessment(
        context,
        status=(
            MedicationPertinenceStatus.PERTINENTE
            if supported
            else MedicationPertinenceStatus.POSIBLE_GLOSA
        ),
        chain=MedicationSupportChain(
            orden=MedicationSupportState.PRESENTE if supported else MedicationSupportState.AUSENTE,
            administracion=MedicationSupportState.NO_APLICA,
            facturacion=MedicationSupportState.NO_APLICA,
        ),
        reasons=(
            ["Fórmula de egreso respaldada; no requiere administración ni cobro institucional."]
            if supported
            else ["La fórmula de egreso no tiene una orden o formulación trazable."]
        ),
        rules=["MED-CTX-EGRESO" if supported else "MED-GLOSA-ORDEN"],
    )


def _standard_issues(context: _MedicationEvaluationContext) -> tuple[list[str], list[str]]:
    reasons: list[str] = []
    rules: list[str] = []
    if context.association == MedicationInvoiceAssociationStatus.AMBIGUA:
        reasons.append("La línea facturada tiene varios esquemas clínicos candidatos.")
        rules.append("MED-REV-ASOCIACION-FACTURA")
    if not context.ordered:
        reasons.append("No se encontró orden o formulación trazable.")
        rules.append("MED-GLOSA-ORDEN")
    if not context.administered:
        reasons.append("No se encontró evidencia asistencial de suministro.")
        rules.append("MED-GLOSA-ADMINISTRACION")
    if context.invoice_state == MedicationInvoiceState.VALIDA and not context.billed:
        reasons.append("No se encontró el medicamento en la factura válida disponible del caso.")
        rules.append("MED-GLOSA-FACTURACION")
    elif context.invoice_state == MedicationInvoiceState.INSUFICIENTE:
        reasons.append("La extracción de la factura es insuficiente para completar la conciliación.")
        rules.append("MED-REV-FACTURA-INSUFICIENTE")
    elif context.invoice_state == MedicationInvoiceState.AUSENTE:
        reasons.append("No existe una factura disponible para completar la conciliación.")
        rules.append("MED-REV-SIN-FACTURA")

    comparison = context.quantity_comparison
    if (
        comparison.estado == MedicationQuantityComparisonStatus.COMPARABLE
        and comparison.cantidad_clinica is not None
        and comparison.cantidad_facturada is not None
        and comparison.cantidad_facturada > comparison.cantidad_clinica
    ):
        reasons.append("La cantidad facturada supera la cantidad administrada en unidades equivalentes.")
        rules.append("MED-GLOSA-CANTIDAD")
    elif comparison.estado == MedicationQuantityComparisonStatus.AMBIGUA:
        reasons.append(comparison.motivo)
        rules.append("MED-REV-CANTIDAD")
    elif (
        comparison.estado == MedicationQuantityComparisonStatus.COMPARABLE
        and comparison.cantidad_clinica != comparison.cantidad_facturada
    ):
        reasons.append("Las cantidades equivalentes presentan una diferencia que requiere conciliación.")
        rules.append("MED-REV-CANTIDAD")
    return _unique(reasons), _unique(rules)


def _standard_state(
    context: _MedicationEvaluationContext,
    rules: Iterable[str],
) -> MedicationPertinenceStatus:
    rules = list(rules)
    if context.invoice_state != MedicationInvoiceState.VALIDA:
        return MedicationPertinenceStatus.REVISAR
    if context.association == MedicationInvoiceAssociationStatus.AMBIGUA:
        return MedicationPertinenceStatus.REVISAR
    if any(rule.startswith("MED-GLOSA-") for rule in rules):
        return MedicationPertinenceStatus.POSIBLE_GLOSA
    if any(rule.startswith("MED-REV-") for rule in rules):
        return MedicationPertinenceStatus.REVISAR
    return MedicationPertinenceStatus.PERTINENTE


def _billing_support_state(context: _MedicationEvaluationContext) -> MedicationSupportState:
    if context.association == MedicationInvoiceAssociationStatus.AMBIGUA:
        return MedicationSupportState.NO_EVALUABLE
    if context.billed:
        return MedicationSupportState.PRESENTE
    if context.invoice_state == MedicationInvoiceState.VALIDA:
        return MedicationSupportState.AUSENTE
    return MedicationSupportState.NO_EVALUABLE


def _standard_assessment(context: _MedicationEvaluationContext) -> MedicationPertinenceAssessment:
    reasons, rules = _standard_issues(context)
    return _assessment(
        context,
        status=_standard_state(context, rules),
        chain=MedicationSupportChain(
            orden=(
                MedicationSupportState.PRESENTE
                if context.ordered
                else MedicationSupportState.AUSENTE
            ),
            administracion=(
                MedicationSupportState.PRESENTE
                if context.administered
                else MedicationSupportState.AUSENTE
            ),
            facturacion=_billing_support_state(context),
        ),
        reasons=reasons or ["Orden, suministro y facturación cuentan con soporte trazable."],
        rules=rules or ["MED-PERTINENTE-CADENA"],
    )


def _assess_medication(context: _MedicationEvaluationContext) -> MedicationPertinenceAssessment:
    if context.antecedent:
        return _antecedent_assessment(context)
    if context.discharge:
        return _discharge_assessment(context)
    return _standard_assessment(context)


def evaluate_medication_pertinence(
    medications: Iterable[dict[str, Any]],
    *,
    invoice_available: bool | None = None,
    invoice_state: MedicationInvoiceState | str | None = None,
    support_documents: Iterable[dict[str, str]] = (),
) -> list[dict[str, Any]]:
    evaluated: list[dict[str, Any]] = []
    support_documents = list(support_documents)
    resolved_invoice_state = _resolve_invoice_state(
        invoice_available=invoice_available,
        invoice_state=invoice_state,
    )
    for raw in medications:
        item = dict(raw)
        context = _build_evaluation_context(
            item,
            invoice_state=resolved_invoice_state,
            support_documents=support_documents,
        )
        item["pertinencia"] = _assess_medication(context).model_dump(mode="json")
        evaluated.append(item)
    return evaluated


def _sources_by_support(item: dict[str, Any]) -> dict[str, list[str]]:
    result = {"orden": [], "administracion": [], "facturacion": []}
    for evidence in item.get("evidencias") or []:
        if not isinstance(evidence, dict):
            continue
        role = str(evidence.get("role") or "")
        source = _clean(evidence.get("fuente"))
        if role in result and source:
            result[role].append(source)
    return {key: _unique(values) for key, values in result.items()}


def build_medication_glosa_findings(medications: Iterable[dict[str, Any]]) -> list[dict[str, Any]]:
    findings: list[dict[str, Any]] = []
    for item in medications:
        assessment = item.get("pertinencia")
        if not isinstance(assessment, dict):
            continue
        state = str(assessment.get("estado") or "")
        if state not in {
            MedicationPertinenceStatus.REVISAR.value,
            MedicationPertinenceStatus.POSIBLE_GLOSA.value,
        }:
            continue
        comparison = assessment.get("comparacion_cantidad")
        findings.append(
            {
                "key": str(item.get("key") or ""),
                "medicamento": str(item.get("nombre") or item.get("medicamento") or ""),
                "presentacion": str(item.get("presentacion") or ""),
                "codigo_referencia": str(item.get("codigo_referencia") or ""),
                "posologia": str(item.get("posologia") or ""),
                "dosis": str(item.get("dosis") or ""),
                "cantidad": item.get("cantidad"),
                "unidad_cantidad": str(item.get("unidad_cantidad") or ""),
                "estado": state,
                "asociacion_factura": str(item.get("asociacion_factura") or "no_evaluable"),
                "cadena": dict(assessment.get("cadena") or {}),
                "comparacion_cantidad": (
                    dict(comparison) if isinstance(comparison, dict) else {}
                ),
                "motivos": _unique(assessment.get("motivos") or []),
                "fuentes": _unique(assessment.get("fuentes") or []),
                "fuentes_por_eslabon": _sources_by_support(item),
                "evidencias": _unique(assessment.get("evidencias") or [])[:3],
                "justificacion_clinica": _clean(assessment.get("justificacion_clinica")),
            }
        )
    priority = {
        MedicationPertinenceStatus.POSIBLE_GLOSA.value: 0,
        MedicationPertinenceStatus.REVISAR.value: 1,
    }
    return sorted(
        findings,
        key=lambda item: (
            priority.get(str(item.get("estado")), 99),
            normalize_medication_key(item.get("medicamento")),
            normalize_medication_key(item.get("dosis")),
            normalize_medication_key(item.get("posologia")),
        ),
    )


def _review_evidence(
    item: dict[str, Any],
    review: dict[str, Any],
) -> tuple[list[str], list[str]]:
    evidence_by_id = {
        str(evidence.get("evidence_id") or ""): _clean(evidence.get("evidencia"))
        for evidence in item.get("evidencias") or []
        if isinstance(evidence, dict) and str(evidence.get("evidence_id") or "")
    }
    requested_ids = _unique(review.get("evidence_ids") or review.get("evidencias") or [])
    valid_ids = [evidence_id for evidence_id in requested_ids if evidence_id in evidence_by_id]
    return valid_ids, _unique(evidence_by_id[evidence_id] for evidence_id in valid_ids)


def _is_redundant_rationale(rationale: str, reasons: Iterable[str]) -> bool:
    normalized = normalize_medication_key(rationale)
    return any(
        normalized == normalize_medication_key(reason)
        or normalized in normalize_medication_key(reason)
        or normalize_medication_key(reason) in normalized
        for reason in reasons
        if normalize_medication_key(reason)
    )


def apply_clinical_pertinence_reviews(
    medications: Iterable[dict[str, Any]],
    reviews: Iterable[dict[str, Any]],
) -> list[dict[str, Any]]:
    review_by_key = {
        str(review.get("key") or ""): review
        for review in reviews
        if isinstance(review, dict) and str(review.get("key") or "")
    }
    result: list[dict[str, Any]] = []
    for raw in medications:
        item = dict(raw)
        review = review_by_key.get(str(item.get("key") or ""))
        assessment = dict(item.get("pertinencia") or {})
        if not review or not assessment:
            result.append(item)
            continue
        reviewed_state = str(review.get("estado") or "").strip().lower()
        rationale = _clean(review.get("justificacion"))
        valid_ids, evidence = _review_evidence(item, review)
        current_state = str(assessment.get("estado") or "")
        if (
            reviewed_state == MedicationPertinenceStatus.POSIBLE_GLOSA.value
            and rationale
            and valid_ids
        ):
            assessment["estado"] = MedicationPertinenceStatus.POSIBLE_GLOSA.value
            if not _is_redundant_rationale(rationale, assessment.get("motivos", [])):
                assessment["justificacion_clinica"] = rationale
                assessment["motivos"] = _unique([*assessment.get("motivos", []), rationale])
            assessment["evidencias"] = _unique([*assessment.get("evidencias", []), *evidence])
            assessment["evidencias_clinicas_ids"] = valid_ids
            assessment["codigos_regla"] = _unique(
                [*assessment.get("codigos_regla", []), "MED-GLOSA-PERTINENCIA-CLINICA"]
            )
            assessment["origen"] = "reglas+llm"
        elif (
            reviewed_state == MedicationPertinenceStatus.REVISAR.value
            and current_state == MedicationPertinenceStatus.PERTINENTE.value
            and rationale
            and valid_ids
        ):
            assessment["estado"] = MedicationPertinenceStatus.REVISAR.value
            assessment["justificacion_clinica"] = rationale
            assessment["motivos"] = _unique([*assessment.get("motivos", []), rationale])
            assessment["evidencias"] = _unique([*assessment.get("evidencias", []), *evidence])
            assessment["evidencias_clinicas_ids"] = valid_ids
            assessment["codigos_regla"] = _unique(
                [*assessment.get("codigos_regla", []), "MED-REV-PERTINENCIA-CLINICA"]
            )
            assessment["origen"] = "reglas+llm"
        item["pertinencia"] = MedicationPertinenceAssessment.model_validate(assessment).model_dump(
            mode="json"
        )
        result.append(item)
    return result
