from __future__ import annotations

import re
from datetime import datetime

from pydantic import BaseModel, ConfigDict, field_validator


_DOCUMENT_TYPES = {
    "AS",
    "CC",
    "CD",
    "CE",
    "CN",
    "DE",
    "MS",
    "NIT",
    "PA",
    "PE",
    "PT",
    "RC",
    "SC",
    "SI",
    "TI",
}
_CIE10_CODE_PATTERN = re.compile(r"^[A-TV-Z]\d{2}[0-9A-Z]?(?:\.[0-9A-Z]{1,2})?$", flags=re.IGNORECASE)
_CUPS_CODE_PATTERN = re.compile(r"^[A-Z0-9]{4,18}$", flags=re.IGNORECASE)
_SERVICE_CODE_PATTERN = re.compile(r"^[A-Z0-9][A-Z0-9\- ]{0,29}$", flags=re.IGNORECASE)


class RipsValueObject(BaseModel):
    model_config = ConfigDict(frozen=True, extra="forbid", str_strip_whitespace=True)


class DocumentoIdentificacion(RipsValueObject):
    tipo: str
    numero: str

    @field_validator("tipo")
    @classmethod
    def validate_tipo(cls, value: str) -> str:
        normalized = str(value or "").strip().upper()
        if normalized not in _DOCUMENT_TYPES:
            raise ValueError("Tipo de documento no soportado para RIPS.")
        return normalized

    @field_validator("numero")
    @classmethod
    def validate_numero(cls, value: str) -> str:
        normalized = re.sub(r"[^A-Z0-9]", "", str(value or "").strip().upper())
        if not normalized:
            raise ValueError("El número de documento es obligatorio.")
        return normalized


class CodigoPrestador(RipsValueObject):
    value: str

    @field_validator("value")
    @classmethod
    def validate_value(cls, value: str) -> str:
        normalized = re.sub(r"\D", "", str(value or "").strip())
        if not normalized:
            raise ValueError("El código del prestador es obligatorio.")
        return normalized


class CodigoCIE10(RipsValueObject):
    value: str

    @field_validator("value")
    @classmethod
    def validate_value(cls, value: str) -> str:
        normalized = str(value or "").strip().upper()
        if not _CIE10_CODE_PATTERN.match(normalized):
            raise ValueError("Código CIE-10 inválido para RIPS.")
        return normalized


class CodigoCUPS(RipsValueObject):
    value: str

    @field_validator("value")
    @classmethod
    def validate_value(cls, value: str) -> str:
        normalized = str(value or "").strip().upper()
        if not _CUPS_CODE_PATTERN.match(normalized):
            raise ValueError("Código CUPS inválido para RIPS.")
        return normalized


class CodigoTecnologiaSalud(RipsValueObject):
    value: str

    @field_validator("value")
    @classmethod
    def validate_value(cls, value: str) -> str:
        normalized = str(value or "").strip().upper()
        if not _SERVICE_CODE_PATTERN.match(normalized):
            raise ValueError("Código de tecnología en salud inválido para RIPS.")
        return normalized


class FechaRips(RipsValueObject):
    value: str

    @field_validator("value")
    @classmethod
    def validate_value(cls, value: str) -> str:
        normalized = str(value or "").strip()
        datetime.strptime(normalized, "%Y-%m-%d")
        return normalized


class FechaHoraRips(RipsValueObject):
    value: str

    @field_validator("value")
    @classmethod
    def validate_value(cls, value: str) -> str:
        normalized = str(value or "").strip()
        datetime.strptime(normalized, "%Y-%m-%d %H:%M")
        return normalized

