"""Runtime configuration and risk scoring helpers for UPF."""

from dataclasses import dataclass, field
from typing import Dict, FrozenSet, List

from upf.redaction.text import RedactionMode


# Risk weights per entity type
_RISK_WEIGHTS: Dict[str, int] = {
    "CREDIT_CARD": 5,
    "IBAN": 5,
    "PESEL": 5,
    "BR_CPF": 5,
    "PT_NISS": 5,
    "SECRET": 5,
    "PT_NIF": 4,
    "UUID": 4,
    "EMAIL": 3,
    "PHONE": 3,
    "ADDRESS": 3,
    "DATE_OF_BIRTH": 3,
    "URL": 2,
    "LONG_NUMERIC_ID": 2,
    "NAME": 2,
    "ORG": 1,
}

# Per-finding confidence weights (0.0–1.0).
# Deterministic validators (checksum-backed) get 1.0; heuristic detectors lower.
_CONFIDENCE_WEIGHTS: Dict[str, float] = {
    "CREDIT_CARD": 0.95,
    "IBAN": 1.0,
    "PESEL": 0.95,
    "BR_CPF": 1.0,
    "PT_NISS": 1.0,
    "PT_NIF": 1.0,
    "SECRET": 0.85,
    "UUID": 1.0,
    "EMAIL": 1.0,
    "PHONE": 0.80,
    "ADDRESS": 0.75,
    "DATE_OF_BIRTH": 0.95,
    "URL": 0.90,
    "LONG_NUMERIC_ID": 0.70,
    "NAME": 0.65,
    "ORG": 0.60,
}

# Types whose presence alone forces 'high' risk level (deterministic floor).
_DEFAULT_DETERMINISTIC_FLOOR: FrozenSet[str] = frozenset({
    "CREDIT_CARD", "IBAN", "PESEL", "BR_CPF", "PT_NISS", "PT_NIF", "SECRET",
})


def compute_risk_score(entities: List[dict]) -> int:
    """Return total risk score for a list of entity dicts (each has a 'type' key)."""
    return sum(_RISK_WEIGHTS.get(e.get("type", ""), 1) for e in entities)


def compute_confidence(entity: dict) -> float:
    """Return confidence (0.0–1.0) for a single entity finding."""
    return _CONFIDENCE_WEIGHTS.get(entity.get("type", ""), 0.5)


def compute_risk_level(
    entities: List[dict],
    low_threshold: float = 0.40,
    high_threshold: float = 0.75,
    deterministic_floor_types: FrozenSet[str] = _DEFAULT_DETERMINISTIC_FLOOR,
) -> str:
    """Return 'low', 'medium', or 'high' based on aggregated confidence + deterministic floor.

    Deterministic floor: any finding in *deterministic_floor_types* immediately
    classifies the request as 'high', bypassing threshold math.
    """
    if not entities:
        return "low"

    # Deterministic floor: any high-certainty type triggers 'high' immediately
    for e in entities:
        if e.get("type") in deterministic_floor_types:
            return "high"

    # Weighted-average confidence across all findings
    avg_conf = sum(compute_confidence(e) for e in entities) / len(entities)

    if avg_conf >= high_threshold:
        return "high"
    if avg_conf >= low_threshold:
        return "medium"
    return "low"


@dataclass
class UPFConfig:
    """Configuration for detector layers, redaction behavior, and risk policy."""

    # ---------- detection toggles ----------
    redact_names: bool = True
    redact_emails: bool = True
    redact_phones: bool = True
    redact_secrets: bool = True
    redact_addresses: bool = True
    redact_urls: bool = True
    redact_numeric_ids: bool = True
    redact_national_ids: bool = True   # governs PT_NISS and similar

    # ---------- pipeline layer toggles ----------
    use_rust_core_first: bool = False
    use_ml_ner: bool = True
    use_multilingual: bool = True
    use_relationship_detector: bool = True
    blur_faces: bool = True
    face_blur_strength: int = 51
    blur_signatures: bool = False
    signature_blur_strength: int = 23

    # ---------- redaction mode ----------
    redaction_mode: RedactionMode = field(default=RedactionMode.LABEL)

    # ---------- risk gating ----------
    # "legacy"    — redact any finding (original behaviour, default)
    # "threshold" — classify low/medium/high via aggregated confidence, apply policy
    risk_mode: str = "legacy"
    low_threshold: float = 0.40
    high_threshold: float = 0.75
    block_high_risk: bool = False
    deterministic_floor_types: FrozenSet[str] = field(
        default_factory=lambda: _DEFAULT_DETERMINISTIC_FLOOR
    )
