from __future__ import annotations

from enum import StrEnum
from typing import Any

from pydantic import BaseModel, ConfigDict, Field, field_validator


class MedicationCaseStatus(StrEnum):
    ADMINISTRADO = "administrado"
    FORMULADO = "formulado"
    ORDENADO = "ordenado"
    FACTURADO = "facturado"
    ANTECEDENTE = "antecedente"
    OTRO = "otro"


class MedicationPertinenceStatus(StrEnum):
    PERTINENTE = "pertinente"
    REVISAR = "revisar"
    POSIBLE_GLOSA = "posible_glosa"


class MedicationSupportState(StrEnum):
    PRESENTE = "presente"
    AUSENTE = "ausente"
    NO_APLICA = "no_aplica"
    NO_EVALUABLE = "no_evaluable"


class MedicationEvidenceRole(StrEnum):
    ORDEN = "orden"
    ADMINISTRACION = "administracion"
    FACTURACION = "facturacion"
    CONTEXTO = "contexto"


class MedicationInvoiceAssociationStatus(StrEnum):
    EXACTA = "exacta"
    INEQUIVOCA = "inequivoca"
    AMBIGUA = "ambigua"
    SIN_COINCIDENCIA = "sin_coincidencia"
    NO_EVALUABLE = "no_evaluable"


class MedicationQuantityComparisonStatus(StrEnum):
    COMPARABLE = "comparable"
    AMBIGUA = "ambigua"
    NO_EVALUABLE = "no_evaluable"
    NO_APLICA = "no_aplica"


class MedicationEvidence(BaseModel):
    model_config = ConfigDict(extra="ignore", str_strip_whitespace=True)

    evidence_id: str = ""
    fuente: str
    estado: MedicationCaseStatus
    document_type: str = ""
    document_name: str = ""
    pagina: str = ""
    role: MedicationEvidenceRole = MedicationEvidenceRole.CONTEXTO
    fecha: str = ""
    cantidad: int | float | None = None
    unidad: str = ""
    evidencia: str = ""


class MedicationSupportChain(BaseModel):
    model_config = ConfigDict(extra="ignore", str_strip_whitespace=True)

    orden: MedicationSupportState = MedicationSupportState.NO_EVALUABLE
    administracion: MedicationSupportState = MedicationSupportState.NO_EVALUABLE
    facturacion: MedicationSupportState = MedicationSupportState.NO_EVALUABLE


class MedicationSupportEvidence(BaseModel):
    model_config = ConfigDict(extra="ignore", str_strip_whitespace=True)

    orden: list[str] = Field(default_factory=list)
    administracion: list[str] = Field(default_factory=list)
    facturacion: list[str] = Field(default_factory=list)


class MedicationQuantityComparison(BaseModel):
    model_config = ConfigDict(extra="ignore", str_strip_whitespace=True)

    estado: MedicationQuantityComparisonStatus = MedicationQuantityComparisonStatus.NO_EVALUABLE
    cantidad_clinica: int | float | None = None
    unidad_clinica: str = ""
    cantidad_facturada: int | float | None = None
    unidad_facturada: str = ""
    motivo: str = ""


class MedicationPertinenceAssessment(BaseModel):
    model_config = ConfigDict(extra="ignore", str_strip_whitespace=True)

    estado: MedicationPertinenceStatus
    cadena: MedicationSupportChain = Field(default_factory=MedicationSupportChain)
    soportes: MedicationSupportEvidence = Field(default_factory=MedicationSupportEvidence)
    comparacion_cantidad: MedicationQuantityComparison = Field(
        default_factory=MedicationQuantityComparison
    )
    motivos: list[str] = Field(default_factory=list)
    codigos_regla: list[str] = Field(default_factory=list)
    fuentes: list[str] = Field(default_factory=list)
    evidencias: list[str] = Field(default_factory=list)
    evidencias_clinicas_ids: list[str] = Field(default_factory=list)
    justificacion_clinica: str = ""
    origen: str = "reglas"
    version: str = "v2"


class MedicamentoCaso(BaseModel):
    """Esquema farmacológico consolidado, separado de su presentación visual."""

    model_config = ConfigDict(extra="ignore", str_strip_whitespace=True)

    key: str
    nombre: str
    presentacion: str = ""
    posologia: str = ""
    dosis: str = ""
    cantidad: int | float | None = None
    cantidad_clinica: int | float | None = None
    cantidad_facturada: int | float | None = None
    unidad_cantidad: str = ""
    estados: list[MedicationCaseStatus] = Field(default_factory=list)
    codigo_facturacion: str = ""
    codigo_referencia: str = ""
    codigo_estado: str = "no_identificado"
    fuentes: list[str] = Field(default_factory=list)
    evidencias: list[MedicationEvidence] = Field(default_factory=list)
    discrepancia_cantidad: bool = False
    asociacion_factura: MedicationInvoiceAssociationStatus = (
        MedicationInvoiceAssociationStatus.NO_EVALUABLE
    )
    candidatos_factura: list[str] = Field(default_factory=list)
    pertinencia: MedicationPertinenceAssessment | None = None

    @field_validator("estados", mode="before")
    @classmethod
    def _normalize_statuses(cls, value: Any) -> Any:
        if isinstance(value, str):
            return [part.strip().lower() for part in value.split("·") if part.strip()]
        return value
