from __future__ import annotations

import re
import unicodedata
from collections.abc import Iterable, Mapping
from dataclasses import dataclass
from typing import Any


def normalized_clinical_text(value: Any) -> str:
    text = unicodedata.normalize("NFKD", str(value or ""))
    ascii_text = "".join(char for char in text if not unicodedata.combining(char))
    return " ".join(re.findall(r"[A-Z0-9]+", ascii_text.upper()))


@dataclass(frozen=True)
class DeterministicPopRule:
    code: str
    procedure_terms: tuple[str, ...]
    finding_terms: tuple[str, ...]


_RULES = (
    DeterministicPopRule("S420", ("OSTEOSINTESIS", "REDUCCION"), ("FRACTURA", "CLAVICULA")),
    DeterministicPopRule("M241", ("CONDROPLASTIA",), ("CONDral", "CARTILAGO")),
    DeterministicPopRule("M240", ("EXTRACCION", "CUERPOS"), ("CUERPOS", "LIBRES")),
    DeterministicPopRule("M242", ("REPARACION", "LIGAMENTO"), ("LIGAMENTO",)),
)


def deterministic_pop_codes(procedure_pop: str, finding: str) -> list[str]:
    """Return codes only when both POP procedure and surgical finding support a rule."""
    procedure_key = normalized_clinical_text(procedure_pop)
    finding_key = normalized_clinical_text(finding)
    result: list[str] = []
    for rule in _RULES:
        procedure_matches = sum(term.upper() in procedure_key for term in rule.procedure_terms)
        finding_matches = sum(term.upper() in finding_key for term in rule.finding_terms)
        if procedure_matches and finding_matches:
            result.append(rule.code)
    return result


def compatible_declared_diagnoses(
    procedure_pop: str,
    finding: str,
    declared: Iterable[Mapping[str, Any]],
) -> list[Mapping[str, Any]]:
    supported = set(deterministic_pop_codes(procedure_pop, finding))
    ignored = {"DE", "DEL", "LA", "EL", "LOS", "LAS", "CON", "MAS", "UNA", "UNO", "DOS"}
    clinical_tokens = {
        token
        for token in normalized_clinical_text(f"{procedure_pop} {finding}").split()
        if token not in ignored and len(token) > 2
    }
    matches: list[Mapping[str, Any]] = []
    for entry in declared:
        code = re.sub(r"[^A-Z0-9]", "", str(entry.get("codigo") or "").upper())
        description = normalized_clinical_text(entry.get("descripcion") or entry.get("diagnostico"))
        overlap = {token for token in description.split() if token not in ignored} & clinical_tokens
        if code in supported or len(overlap) >= 2:
            matches.append(entry)
    return matches


def compose_postoperative_description(
    official_diagnosis: str,
    finding: str,
    procedure_pop: str,
) -> str:
    """Compose the existing clinical-description field without duplicating the official concept."""
    parts: list[str] = []
    if finding and normalized_clinical_text(finding) != normalized_clinical_text(official_diagnosis):
        parts.append(finding.strip().rstrip("."))
    if procedure_pop:
        parts.append(f"POSTOPERATORIO {procedure_pop.strip().rstrip('.')}" )
    return ". ".join(parts) + ("." if parts else "")
