"""Selección segura de resúmenes clínicos en documentos quirúrgicos."""

from __future__ import annotations

import re
import unicodedata
from dataclasses import dataclass
from typing import Any


_CLINICAL_SIGNAL_PATTERN = re.compile(
    r"\b(?:diagn[oó]st|fractur|lesi[oó]n|hallazg|proced|cirug|interven|incisi[oó]n|"
    r"anestesi|complicaci[oó]n|conclusi[oó]n|evoluci[oó]n|tratamiento|manejo|"
    r"biopsia|resecci[oó]n|reparaci[oó]n|sutura|terapia|quir[uú]rg|realiz)\w*\b",
    re.IGNORECASE,
)
_ADMINISTRATIVE_PATTERN = re.compile(
    r"\b(?:nombre|identificaci[oó]n|documento|paciente|caso|historia|factura|"
    r"prestador|instituci[oó]n|eps|aseguradora|nit|fecha|tel[eé]fono|direcci[oó]n)\b\s*[:#-]",
    re.IGNORECASE,
)
_PERSON_NAME_PATTERN = re.compile(
    r"^[A-ZÁÉÍÓÚÜÑ][A-ZÁÉÍÓÚÜÑ'’-]*(?:\s+[A-ZÁÉÍÓÚÜÑ][A-ZÁÉÍÓÚÜÑ'’-]*){1,5}$"
)
_LOW_QUALITY_VALUES = {
    "",
    "...",
    "no especificado",
    "no disponible",
    "sin informacion",
    "sin información",
    "resumen estructurado",
    "descripcion estructurada",
    "descripción estructurada",
    "hallazgos estructurados",
}


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


def _key(value: Any) -> str:
    normalized = unicodedata.normalize("NFKD", _clean(value).casefold())
    return "".join(char for char in normalized if not unicodedata.combining(char))


@dataclass(frozen=True, slots=True)
class SummaryCandidateAssessment:
    field: str
    text: str
    usable: bool
    reason: str | None = None


@dataclass(frozen=True, slots=True)
class SurgicalSummarySelection:
    field: str | None
    text: str
    candidates: tuple[SummaryCandidateAssessment, ...]

    @property
    def selected(self) -> bool:
        return bool(self.field and self.text)

    @property
    def rejected_fields(self) -> tuple[str, ...]:
        return tuple(item.field for item in self.candidates if not item.usable and item.text)

    @property
    def rejection_reasons(self) -> tuple[str, ...]:
        return tuple(
            f"{item.field}:{item.reason}"
            for item in self.candidates
            if not item.usable and item.text and item.reason
        )


def assess_summary_candidate(
    value: Any,
    *,
    field: str,
    patient_name: Any = "",
    patient_id: Any = "",
    case_number: Any = "",
) -> SummaryCandidateAssessment:
    text = _clean(value)
    if not text:
        return SummaryCandidateAssessment(field=field, text="", usable=False, reason="summary_empty")
    if _key(text) in {_key(patient_name), _key(patient_id), _key(case_number)} - {""}:
        return SummaryCandidateAssessment(field=field, text=text, usable=False, reason="summary_identity_only")
    if _PERSON_NAME_PATTERN.fullmatch(text) and not _CLINICAL_SIGNAL_PATTERN.search(text):
        return SummaryCandidateAssessment(field=field, text=text, usable=False, reason="summary_identity_only")
    if _key(text) in {_key(value) for value in _LOW_QUALITY_VALUES}:
        return SummaryCandidateAssessment(field=field, text=text, usable=False, reason="summary_low_quality")
    if _ADMINISTRATIVE_PATTERN.search(text) and not _CLINICAL_SIGNAL_PATTERN.search(text):
        return SummaryCandidateAssessment(field=field, text=text, usable=False, reason="summary_administrative")
    if len(text) < 15 or not _CLINICAL_SIGNAL_PATTERN.search(text):
        return SummaryCandidateAssessment(
            field=field,
            text=text,
            usable=False,
            reason="summary_without_clinical_signals",
        )
    return SummaryCandidateAssessment(field=field, text=text, usable=True)


def select_surgical_summary(
    source: Any,
    *,
    patient_name: Any = "",
    patient_id: Any = "",
    case_number: Any = "",
) -> SurgicalSummarySelection:
    """Usa ``rs`` clínico y cae a ``cl`` cuando ``rs`` está contaminado."""
    def value_for(field: str) -> Any:
        aliases = {"rs": ("rs", "resumen_clinico"), "cl": ("cl", "conclusion")}[field]
        if isinstance(source, dict):
            for alias in aliases:
                if source.get(alias) is not None:
                    return source.get(alias)
            return ""
        for alias in aliases:
            value = getattr(source, alias, None)
            if value is not None:
                return value
        return ""

    candidates = tuple(
        assess_summary_candidate(
            value_for(field),
            field=field,
            patient_name=patient_name,
            patient_id=patient_id,
            case_number=case_number,
        )
        for field in ("rs", "cl")
    )
    selected = next((item for item in candidates if item.usable), None)
    return SurgicalSummarySelection(
        field=selected.field if selected else None,
        text=selected.text if selected else "",
        candidates=candidates,
    )


__all__ = [
    "SummaryCandidateAssessment",
    "SurgicalSummarySelection",
    "assess_summary_candidate",
    "select_surgical_summary",
]
