from __future__ import annotations

from typing import Any, Literal

from pydantic import BaseModel, ConfigDict, Field


class ClinicalStructuredModel(BaseModel):
    model_config = ConfigDict(populate_by_name=True, extra="ignore")

    schema_version: Literal["v1"] = Field(default="v1", alias="sv")
    document_type: str = Field(alias="dt")
    patient_name: str = Field(default="No especificado", alias="pn")
    source_notes: str | None = Field(default=None, alias="sn")


class DiagnosticoItem(BaseModel):
    model_config = ConfigDict(populate_by_name=True, extra="ignore")

    codigo: str | None = Field(default=None, alias="c")
    descripcion: str = Field(alias="d")


class ProcedimientoItem(BaseModel):
    model_config = ConfigDict(populate_by_name=True, extra="ignore")

    codigo: str | None = Field(default=None, alias="c")
    descripcion: str = Field(alias="d")


class MedicamentoItem(BaseModel):
    model_config = ConfigDict(populate_by_name=True, extra="ignore")

    codigo: str | None = Field(default=None, alias="c")
    nombre: str = Field(alias="n")
    dosis: str | None = Field(default=None, alias="ds")
    via: str | None = Field(default=None, alias="v")
    frecuencia: str | None = Field(default=None, alias="f")
    cantidad: str | None = Field(default=None, alias="q")


class MedicamentoPrescritoItem(MedicamentoItem):
    diagnostico_contexto: str | None = Field(default=None, alias="dx")


class LaboratorioResultadoItem(BaseModel):
    model_config = ConfigDict(populate_by_name=True, extra="ignore")

    parametro: str = Field(alias="p")
    resultado: str = Field(alias="r")
    rango_normal: str | None = Field(default=None, alias="rn")
    estado: str | None = Field(default=None, alias="e")


class ReferenciaDiagnosticaItem(BaseModel):
    model_config = ConfigDict(populate_by_name=True, extra="ignore")

    tipo: str = Field(alias="t")
    nombre: str = Field(alias="n")
    concepto: str | None = Field(default=None, alias="c")


class ProveedorFactura(BaseModel):
    model_config = ConfigDict(populate_by_name=True, extra="ignore")

    nombre_institucion: str | None = Field(default=None, alias="ni")
    nit: str | None = Field(default=None, alias="nt")
    direccion: str | None = Field(default=None, alias="dr")
    ciudad_departamento: str | None = Field(default=None, alias="cd")


class DatosFactura(BaseModel):
    model_config = ConfigDict(populate_by_name=True, extra="ignore")

    numero_factura: str | None = Field(default=None, alias="nf")
    prefijo: str | None = Field(default=None, alias="pf")
    fecha_emision: str | None = Field(default=None, alias="fe")
    numero_caso: str | None = Field(default=None, alias="nc")
    fecha_vencimiento: str | None = Field(default=None, alias="fv")


class PagadorFactura(BaseModel):
    model_config = ConfigDict(populate_by_name=True, extra="ignore")

    aseguradora_eps: str | None = Field(default=None, alias="ae")
    nit_pagador: str | None = Field(default=None, alias="np")
    tipo_convenio: str | None = Field(default=None, alias="tc")
    numero_autorizacion: str | None = Field(default=None, alias="na")


class PacienteFactura(BaseModel):
    model_config = ConfigDict(populate_by_name=True, extra="ignore")

    nombre_completo: str | None = Field(default=None, alias="nm")
    numero_identificacion: str | None = Field(default=None, alias="id")
    fecha_ingreso: str | None = Field(default=None, alias="fi")
    fecha_egreso: str | None = Field(default=None, alias="fg")
    estancia_hospitalaria: str | None = Field(default=None, alias="eh")


class ServicioFacturaItem(BaseModel):
    model_config = ConfigDict(populate_by_name=True, extra="ignore")

    concepto: str | None = Field(default=None, alias="cp")
    codigo_cups: str | None = Field(default=None, alias="cc")
    fecha_servicio: str | None = Field(default=None, alias="fs")
    codigo_facturacion: str | None = Field(default=None, alias="cf")
    codigo_referencia: str | None = Field(default=None, alias="cr")
    descripcion: str | None = Field(default=None, alias="d")
    cantidad: str | None = Field(default=None, alias="q")
    valor_unitario: str | None = Field(default=None, alias="vu")
    total: str | None = Field(default=None, alias="tt")
    prueba: str | None = Field(default=None, alias="pr")
    estudio: str | None = Field(default=None, alias="es")
    habitacion: str | None = Field(default=None, alias="hb")
    dias: str | None = Field(default=None, alias="ds")
    tarifa: str | None = Field(default=None, alias="tf")
    rol: str | None = Field(default=None, alias="rl")
    profesional: str | None = Field(default=None, alias="pf")
    medicamento: str | None = Field(default=None, alias="md")
    dosis: str | None = Field(default=None, alias="do")


class FacturaLineaCanonicaItem(BaseModel):
    model_config = ConfigDict(populate_by_name=True, extra="ignore")

    fecha_servicio: str | None = Field(default=None, alias="fs")
    codigo_facturacion: str | None = Field(default=None, alias="cf")
    codigo_referencia: str | None = Field(default=None, alias="cr")
    descripcion: str | None = Field(default=None, alias="d")
    categoria: str | None = Field(default=None, alias="ct")
    cantidad: str | None = Field(default=None, alias="q")
    valor_unitario: str | None = Field(default=None, alias="vu")
    total: str | None = Field(default=None, alias="tt")


class ServicioPrefacturaItem(BaseModel):
    model_config = ConfigDict(populate_by_name=True, extra="ignore")

    codigo: str | None = Field(default=None, alias="c")
    descripcion: str = Field(default="No especificado", alias="d")
    cantidad: str | None = Field(default=None, alias="q")
    valor: str | None = Field(default=None, alias="v")


class ServiciosProcedimientosFactura(BaseModel):
    model_config = ConfigDict(populate_by_name=True, extra="ignore")

    procedimientos_quirurgicos: list[ServicioFacturaItem] = Field(default_factory=list, alias="pq")
    examenes_laboratorio: list[ServicioFacturaItem] = Field(default_factory=list, alias="el")
    imagenologia: list[ServicioFacturaItem] = Field(default_factory=list, alias="im")
    hospitalizacion: list[ServicioFacturaItem] = Field(default_factory=list, alias="hs")
    honorarios_medicos: list[ServicioFacturaItem] = Field(default_factory=list, alias="hm")
    medicamentos: list[ServicioFacturaItem] = Field(default_factory=list, alias="me")
    otros_servicios: list[ServicioFacturaItem] = Field(default_factory=list, alias="ot")


class ResumenFinancieroFactura(BaseModel):
    model_config = ConfigDict(populate_by_name=True, extra="ignore")

    total_servicios: str | None = Field(default=None, alias="ts")
    descuentos: str | None = Field(default=None, alias="dc")
    copagos: str | None = Field(default=None, alias="cg")
    valor_total_factura: str | None = Field(default=None, alias="vt")
    valor_en_letras: str | None = Field(default=None, alias="vl")
    observaciones_importantes: str | None = Field(default=None, alias="ob")


class HistoriaClinicaStructured(ClinicalStructuredModel):
    document_type: Literal["historia_clinica"] = Field(default="historia_clinica", alias="dt")
    prestador_servicio: str | None = Field(default=None, alias="ps")
    numero_caso: str | None = Field(default=None, alias="nc")
    identificacion_paciente: str | None = Field(default=None, alias="ip")
    sexo: str | None = Field(default=None, alias="sx")
    edad: str | None = Field(default=None, alias="ed")
    fecha_nacimiento: str | None = Field(default=None, alias="fn")
    fecha_ingreso: str | None = Field(default=None, alias="fi")
    motivo_consulta: str | None = Field(default=None, alias="mc")
    resumen_clinico: str = Field(default="No especificado", alias="rs")
    diagnosticos: list[DiagnosticoItem] = Field(default_factory=list, alias="dx")
    procedimientos: list[ProcedimientoItem] = Field(default_factory=list, alias="pr")
    medicamentos: list[MedicamentoItem] = Field(default_factory=list, alias="md")


class LaboratorioStructured(ClinicalStructuredModel):
    document_type: Literal["laboratorio"] = Field(default="laboratorio", alias="dt")
    fecha_examen: str | None = Field(default=None, alias="fe")
    tipo_examen: str | None = Field(default=None, alias="te")
    resultados: list[LaboratorioResultadoItem] = Field(default_factory=list, alias="rt")
    valores_alterados: list[str] = Field(default_factory=list, alias="va")
    interpretacion: str | None = Field(default=None, alias="ip")
    observaciones: str | None = Field(default=None, alias="ob")


class RadiologiaStructured(ClinicalStructuredModel):
    document_type: Literal["radiologia"] = Field(default="radiologia", alias="dt")
    fecha_estudio: str | None = Field(default=None, alias="fe")
    tipo_estudio: str | None = Field(default=None, alias="te")
    region_anatomica: str | None = Field(default=None, alias="ra")
    tecnica: str | None = Field(default=None, alias="tc")
    hallazgos: str | None = Field(default=None, alias="hl")
    conclusion: str | None = Field(default=None, alias="cl")


class PrescripcionStructured(ClinicalStructuredModel):
    document_type: Literal["prescripcion"] = Field(default="prescripcion", alias="dt")
    fecha: str | None = Field(default=None, alias="fe")
    diagnostico_contexto: str | None = Field(default=None, alias="dx")
    medicamentos: list[MedicamentoPrescritoItem] = Field(default_factory=list, alias="md")
    observaciones: str | None = Field(default=None, alias="ob")


class DocumentoQuirurgicoStructured(ClinicalStructuredModel):
    document_type: Literal["quirurgico"] = Field(default="quirurgico", alias="dt")
    fecha_procedimiento: str | None = Field(default=None, alias="fp")
    procedimiento_principal: str | None = Field(default=None, alias="pp")
    descripcion_procedimiento: str | None = Field(default=None, alias="dp")
    hallazgos: str | None = Field(default=None, alias="hl")
    complicaciones: str | None = Field(default=None, alias="cm")
    conclusion: str | None = Field(default=None, alias="cl")
    diagnosticos: list[DiagnosticoItem] = Field(default_factory=list, alias="dx")
    procedimientos: list[ProcedimientoItem] = Field(default_factory=list, alias="pr")


class FacturaStructured(ClinicalStructuredModel):
    document_type: Literal["factura"] = Field(default="factura", alias="dt")
    proveedor: ProveedorFactura = Field(default_factory=ProveedorFactura, alias="pv")
    datos_factura: DatosFactura = Field(default_factory=DatosFactura, alias="df")
    pagador: PagadorFactura = Field(default_factory=PagadorFactura, alias="pg")
    paciente: PacienteFactura = Field(default_factory=PacienteFactura, alias="pc")
    lineas_canonicas: list[FacturaLineaCanonicaItem] = Field(default_factory=list, alias="lc")
    servicios_procedimientos: ServiciosProcedimientosFactura = Field(
        default_factory=ServiciosProcedimientosFactura,
        alias="sp",
    )
    resumen_financiero: ResumenFinancieroFactura = Field(default_factory=ResumenFinancieroFactura, alias="rf")


class PrefacturaStructured(ClinicalStructuredModel):
    document_type: Literal["prefactura"] = Field(default="prefactura", alias="dt")
    numero_caso: str | None = Field(default=None, alias="nc")
    prestador: str | None = Field(default=None, alias="ps")
    paciente_nombre: str | None = Field(default=None, alias="pnm")
    paciente_identificacion: str | None = Field(default=None, alias="pid")
    servicios: list[ServicioPrefacturaItem] = Field(default_factory=list, alias="svs")
    valor_estimado: str | None = Field(default=None, alias="ve")
    observaciones: str | None = Field(default=None, alias="ob")


class DocumentoGenericoStructured(ClinicalStructuredModel):
    document_type: Literal["generico"] = Field(default="generico", alias="dt")
    titulo: str | None = Field(default=None, alias="tt")
    tipo_inferido: str | None = Field(default=None, alias="ti")
    resumen: str | None = Field(default=None, alias="rs")
    referencias_diagnosticas: list[ReferenciaDiagnosticaItem] = Field(default_factory=list, alias="rd")
    observaciones: str | None = Field(default=None, alias="ob")


CLINICAL_DOCUMENT_MODELS: dict[str, type[ClinicalStructuredModel]] = {
    "historia_clinica": HistoriaClinicaStructured,
    "laboratorio": LaboratorioStructured,
    "radiologia": RadiologiaStructured,
    "prescripcion": PrescripcionStructured,
    "quirurgico": DocumentoQuirurgicoStructured,
    "factura": FacturaStructured,
    "prefactura": PrefacturaStructured,
    "generico": DocumentoGenericoStructured,
}

CLINICAL_SCHEMA_NAMES: dict[str, str] = {
    "historia_clinica": "HistoriaClinicaStructured",
    "laboratorio": "LaboratorioStructured",
    "radiologia": "RadiologiaStructured",
    "prescripcion": "PrescripcionStructured",
    "quirurgico": "DocumentoQuirurgicoStructured",
    "factura": "FacturaStructured",
    "prefactura": "PrefacturaStructured",
    "generico": "DocumentoGenericoStructured",
}


def get_clinical_document_model(document_type: str) -> type[ClinicalStructuredModel]:
    normalized = str(document_type or "").strip().lower() or "generico"
    return CLINICAL_DOCUMENT_MODELS.get(normalized, DocumentoGenericoStructured)


def get_clinical_schema_name(document_type: str) -> str:
    normalized = str(document_type or "").strip().lower() or "generico"
    return CLINICAL_SCHEMA_NAMES.get(normalized, "DocumentoGenericoStructured")


def dump_clinical_model(model: ClinicalStructuredModel) -> dict[str, Any]:
    return model.model_dump(by_alias=True, exclude_none=True)
