from __future__ import annotations

from decimal import Decimal
from enum import StrEnum

from pydantic import BaseModel, ConfigDict, Field, field_serializer


class EstadoAsociacionCosto(StrEnum):
    DIRECTA = "directa"
    PROPORCIONAL = "proporcional"
    INCOMPLETA = "incompleta"


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

    componente: str = Field(alias="cp")
    valor_cobrado: Decimal = Field(default=Decimal("0"), ge=0, alias="vc")
    indices_lineas_canonicas: list[int] = Field(default_factory=list, alias="il")
    codigos_facturacion: list[str] = Field(default_factory=list, alias="cf")
    conceptos_lineas: list[str] = Field(default_factory=list, alias="cn")
    metodo: str = Field(default="sin_asignacion", alias="mt")
    proporcion: Decimal | None = Field(default=None, ge=0, le=1, alias="pr")
    formula: str | None = Field(default=None, alias="fm")
    redondeo: str | None = Field(default=None, alias="rd")
    saldo_no_asignado: Decimal = Field(default=Decimal("0"), ge=0, alias="sa")
    evidencia: list[str] = Field(default_factory=list, alias="ev")

    @field_serializer("valor_cobrado", "proporcion", "saldo_no_asignado", when_used="always")
    def _serialize_decimal(self, value: Decimal | None) -> str | None:
        return format(value, "f") if value is not None else None


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

    estado: EstadoAsociacionCosto = Field(alias="st")
    valor_directo: Decimal = Field(default=Decimal("0"), ge=0, alias="vd")
    componentes: list[ComponenteCostoQuirurgico] = Field(default_factory=list, alias="cp")
    valor_final: Decimal = Field(default=Decimal("0"), ge=0, alias="vf")
    indices_lineas_canonicas: list[int] = Field(default_factory=list, alias="il")
    codigos_facturacion: list[str] = Field(default_factory=list, alias="cf")
    metodo: str = Field(alias="mt")
    formula: str = Field(alias="fm")
    redondeo: str | None = Field(default=None, alias="rd")
    saldo_no_asignado: Decimal = Field(default=Decimal("0"), ge=0, alias="sa")
    indices_saldo_no_asignado: list[int] = Field(default_factory=list, alias="is")
    evidencia: list[str] = Field(default_factory=list, alias="ev")

    @field_serializer("valor_directo", "valor_final", "saldo_no_asignado", when_used="always")
    def _serialize_decimal(self, value: Decimal) -> str:
        return format(value, "f")
