"""
Solution: classify AI use cases by EU AI Act risk level the way Lab 17's script 02 does. A model
answers factual questions about a use case; code applies the Act's rules in order. Then compare
two methods on the same cases, and set the company's own risk tier. Not legal advice.
"""
import math

PROHIBITED = {"a": "subliminal or manipulative techniques", "b": "exploiting vulnerabilities", "c": "social scoring",
              "d": "crime prediction from profiling alone", "e": "untargeted facial image scraping",
              "f": "emotion recognition at work or school", "g": "biometric categorisation by sensitive traits",
              "h": "real-time remote biometric ID for law enforcement",
              "ba": "sexual images of a real person without consent", "bb": "child sexual abuse material"}
AREAS = ["biometrics", "critical_infrastructure", "education", "employment", "essential_services",
         "law_enforcement", "migration", "justice_democracy", "none"]
EXCEPTIONS = ["none", "narrow_procedural_task", "improves_completed_human_activity",
              "detects_patterns_without_replacing_human_review", "preparatory_task"]
ORDER = {"prohibited": 3, "high": 2, "limited": 1, "minimal": 0}


def decide(a: dict) -> tuple[str, str]:
    """The Act's order: Art. 5, then Annex III with Art. 6(3), then Art. 50."""
    p = str(a.get("prohibited_practice", "none")).lower()
    if p in PROHIBITED:
        return "prohibited", f"Art. 5(1)({p}) {PROHIBITED[p]}"
    area = a.get("annex_iii_area", "none")
    if area in AREAS and area != "none":
        exc = a.get("exception", "none")
        if exc == "none" or exc not in EXCEPTIONS or a.get("profiles_people"):
            return "high", f"Annex III, {area}"
        basis = f"Art. 6(3) {exc}, Annex III {area}"
        if a.get("interacts_with_people") or a.get("generates_synthetic_content"):
            return "limited", basis + "; Art. 50"
        return "minimal", basis
    if a.get("interacts_with_people") or a.get("generates_synthetic_content") \
            or a.get("emotion_or_biometric_categorisation"):
        return "limited", "Art. 50"
    return "minimal", "none"


def score(levels: list[str], labels: list[str]) -> dict:
    """right: levels equal to the label. too_low: levels below the label (the costly mistake)."""
    return {"right": sum(l == t for l, t in zip(levels, labels)),
            "too_low": sum(ORDER[l] < ORDER[t] for l, t in zip(levels, labels))}


def mcnemar(a_right: list[bool], b_right: list[bool]) -> dict:
    """Paired comparison on the same cases. Only the cases where exactly one method was right count;
    under "no difference" each is a coin flip. Return {"b_only", "a_only", "p"}: p is the exact
    two-sided binomial tail, 2 x P(X <= min(a_only, b_only)) for X ~ Binomial(a_only + b_only, 1/2), capped at 1."""
    b_only = sum(b and not a for a, b in zip(a_right, b_right))
    a_only = sum(a and not b for a, b in zip(a_right, b_right))
    n, k = a_only + b_only, min(a_only, b_only)
    p = 1.0 if n == 0 else min(1.0, 2 * sum(math.comb(n, i) for i in range(k + 1)) / 2 ** n)
    return {"b_only": b_only, "a_only": a_only, "p": p}


def internal_tier(severity: int, likelihood: int, reversible: bool, affects_people: bool) -> str:
    """severity and likelihood 1-4. Score = severity x likelihood, +4 if it can't be undone,
    +2 if it harms specific people. 16+ critical, 10+ high, 5+ medium, else low."""
    s = severity * likelihood + (0 if reversible else 4) + (2 if affects_people else 0)
    return "critical" if s >= 16 else "high" if s >= 10 else "medium" if s >= 5 else "low"
