import re
import unicodedata


LOWERCASE_LINKS = {"a", "al", "de", "del", "e", "el", "en", "la", "las", "los", "o", "u", "y"}
SPECIAL_WORDS = {
    "spa": "SpA",
    "s.a.": "S.A.",
    "sa": "S.A.",
    "eirl": "EIRL",
    "ltda": "Ltda.",
    "rut": "RUT",
}
NON_TEXT_TYPES = {
    "BOOLEANO", "EMAIL", "FECHA", "NUMERO", "RUT", "RUT_CHILENO",
    "RUT CHILENO", "TELEFONO",
}


def _clean(value: object) -> str:
    return re.sub(r"\s+", " ", "" if value is None else str(value)).strip()


def _capitalize_piece(piece: str) -> str:
    if not piece:
        return piece
    special = SPECIAL_WORDS.get(piece.casefold())
    if special:
        return special
    if re.fullmatch(r"[IVXLCDM]+", piece):
        return piece
    return piece[:1].upper() + piece[1:].lower()


def title_case_es(value: object) -> str:
    """Human title casing with Spanish linking words kept lowercase."""
    text = _clean(value)
    if not text:
        return ""
    words = text.split(" ")
    output: list[str] = []
    for index, word in enumerate(words):
        pieces = re.split(r"([-’'])", word)
        formatted = "".join(
            piece if piece in {"-", "’", "'"} else _capitalize_piece(piece)
            for piece in pieces
        )
        if index and word.casefold() in LOWERCASE_LINKS:
            formatted = word.lower()
        output.append(formatted)
    return " ".join(output)


def sentence_case_es(value: object) -> str:
    text = _clean(value)
    if not text:
        return ""
    return text[:1].upper() + text[1:]


def _semantic_tokens(*values: str | None) -> set[str]:
    joined = "_".join(value or "" for value in values)
    joined = re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", joined)
    normalized = unicodedata.normalize("NFKD", joined)
    normalized = "".join(char for char in normalized if not unicodedata.combining(char))
    return {token for token in re.split(r"[^a-zA-Z0-9]+", normalized.lower()) if token}


def format_document_value(variable: str, value: object, *, field_code: str | None = None,
                          field_type: str | None = None) -> str:
    """Format a substituted value without modifying its stored representation."""
    text = _clean(value)
    if not text:
        return ""
    if text.lower().startswith(("base64:", "data:", "url:")):
        return text
    kind = (field_type or "").strip().upper()
    if kind in NON_TEXT_TYPES or variable.endswith((".rut", ".email", ".telefono")):
        return text
    tokens = _semantic_tokens(variable, field_code)
    if tokens.intersection({"nombre", "nombres", "apellido", "apellidos"}):
        return title_case_es(text)
    if tokens.intersection({"comuna", "ciudad", "region"}):
        return title_case_es(text)
    if tokens.intersection({"nacionalidad", "profesion", "civil"}):
        return sentence_case_es(text.lower())
    return sentence_case_es(text)
