"""Prompt skeletonization.

Replaces PII with semantic role placeholders that preserve the sentence's
intent for an LLM, rather than removing information entirely.

Example:
    "My name is John Smith and my card is 4111-1111-1111-1111"
    → "My name is [PERSON] and my card is [CARD_NUMBER]"
"""
from typing import Dict, List, Union

from upf.redaction.text import _resolve_conflicts

# Semantic labels used in skeletonized output — more natural than raw type names.
_SKELETON_LABELS: Dict[str, str] = {
    "NAME": "PERSON",
    "EMAIL": "EMAIL_ADDRESS",
    "PHONE": "PHONE_NUMBER",
    "DATE_OF_BIRTH": "DATE_OF_BIRTH",
    "CREDIT_CARD": "CARD_NUMBER",
    "IBAN": "BANK_ACCOUNT",
    "PESEL": "ID_NUMBER",
    "BR_CPF": "ID_NUMBER",
    "PT_NIF": "ID_NUMBER",
    "PT_NISS": "ID_NUMBER",
    "SECRET": "TOKEN",
    "URL": "URL",
    "LONG_NUMERIC_ID": "IDENTIFIER",
    "UUID": "IDENTIFIER",
    "ADDRESS": "ADDRESS",
    "ORG": "ORGANIZATION",
}


def skeletonize(
    text: str,
    findings: List[Dict[str, Union[int, str]]],
) -> str:
    """Replace PII spans with semantic role placeholders.

    Unlike LABEL mode which produces ``[REDACTED:NAME]``, skeletonization
    produces ``[PERSON]`` — shorter, more natural for LLM consumption.
    """
    ordered = _resolve_conflicts(findings)

    out: List[str] = []
    cursor = 0
    for item in ordered:
        start = int(item["start"])
        end = int(item["end"])

        if start < cursor or end <= start:
            continue

        out.append(text[cursor:start])
        label = _SKELETON_LABELS.get(str(item["type"]), str(item["type"]))
        out.append(f"[{label}]")
        cursor = end

    out.append(text[cursor:])
    return "".join(out)
