"""
Practice: test a policy check the way Lab 16's script 02 does. The rules below are the lab's own
(policy.py), written while looking at the 100 hand-written requests. You'll write the check that
applies them, score it on the requests as written and as a model reworded them, ask whether the
drop could be luck, find where an AI check changed its answer, and chain the two.

Fill in the TODOs, then run the tests:
    pytest test_policy_practice.py        (locally)
or press "Run tests" on the chapter page.
"""
import math
import re

# The four things the assistant must refuse, as word patterns. Searched in this order, on lower case.
RULES = {
    "people_decision": [
        r"\b(should|decide|decision)\b.*\b(fire|hire|promot\w*|demot\w*|discipline|let go|lay(ed)? off|raise|bonus|rat(e|ing)|renew|extend|keep|reject)\b",
        r"\b(fire|demote|discipline|terminate|termination)\b\s+\w+",
        r"\b(rank|score|pick|choose|approve or deny|approve|deny|rate)\b.*\b(employees?|candidates?|applicants?|agents?|team member|staff|request for a salary|deserves?)\b",
        r"\b(who|which)\b.*\b(deserves?|to keep|to reject|to hire|to fire|laid off)\b",
        r"\bgive \w+ \w+ a (performance )?rating\b",
    ],
    "bulk_personal_data": [
        r"\b(list|export|dump|compile|extract|pull|copy|make a mailing list|spreadsheet|csv|give me all|give me the|show me every)\b.*\b(all|every(one)?|whole)\b.*\b(customers?|employees?|staff|members?|records?|names?|emails?|phone|addresses|IBANs?|salaries|birthdays|case notes|table)\b",
        r"\b(all|every)\b.*\b(email address(es)?|phone numbers?|home addresses|IBANs|salaries|birthdays|personal (emails?|phone))\b",
        r"\bpersonal phone numbers of everyone\b",
        r"\bwhole customer table\b",
    ],
    "special_category": [
        r"\b(medical|health|sick|illness|disabilit\w*|pregnan\w*|cancer|antidepressants?|mental health|chronic)\b.*\b(why|which|who|does|is|did|tell me|history|conditions?|have)\b",
        r"\b(why|which|who|does|is|did|tell me)\b.*\b(medical|health|sick|disabilit\w*|pregnan\w*|cancer|antidepressants?|mental health|chronic illness|allerg\w*)\b",
        r"\b(religion|ethnic\w*|gay|lesbian|sexual orientation|union|voted|political)\b",
    ],
    "credentials": [
        r"\b(password|passcode|api key|access keys?|private key|token|secret( key)?|credentials?|login|2fa|backup codes|shared secret)\b",
    ],
}
# A question about the policy itself, or the user's own account, is allowed: it wins over a rule.
ALLOW = [
    r"\b(policy|policies|process|procedure|rules?|how do (i|customers|we)|how should|what should|where do i|"
    r"what does gdpr|what makes|how many (sick )?days|how long do we|is it okay|can i export my own|my own)\b",
]


def rule_check(text):
    """The rules' verdict on one request, as {"category": ..., "rule": ...}.
    Lower-case the text, then go through RULES in order (category by category, pattern by
    pattern) and stop at the first pattern that re.search finds:
      - if any ALLOW pattern also matches: {"category": "none", "rule": "ALLOW"}
      - otherwise: {"category": <category>, "rule": "<category>[<index>]"}, e.g. "credentials[0]"
    Nothing matched: {"category": "none", "rule": None}."""
    # TODO
    return {"category": "none", "rule": None}


def score(categories, kinds):
    """How a check did on a set of requests. `categories[i]` is its verdict on request i ("none"
    means allowed, anything else blocked); `kinds[i]` is "violation", "normal" or "tricky".
    Return {"violations_blocked": n, "normal_blocked": n, "tricky_blocked": n}."""
    # TODO
    return {"violations_blocked": 0, "normal_blocked": 0, "tricky_blocked": 0}


def mcnemar_p(a, b):
    """Exact two-sided McNemar test on paired yes/no results (a[i], b[i] for the same request).
    Count only the requests where they disagree: a_only (a yes, b no) and b_only. Under "no
    difference" each disagreement is a coin flip, so p = 2 * P(X <= min(a_only, b_only)) for
    X ~ Binomial(a_only + b_only, 1/2), capped at 1. No disagreements: 1.0."""
    # TODO
    return 1.0


def changed(runs):
    """`runs` is the same check's verdicts on the same requests, one list per try. Return the
    indexes of the requests where block vs. allow wasn't the same on every try (a different
    category with the same block doesn't count), in order."""
    # TODO
    return []


def chain(texts, ai_categories):
    """Rules first; the AI only sees what the rules let through. For each request return
    {"category": ..., "by": "rules"} when the rules block it, else {"category": ai_categories[i],
    "by": "ai"} (the AI was asked, whatever it said)."""
    # TODO
    return []
