#!/usr/bin/env python3
"""Original offline teaching exercise. All review and test records are fictional."""
import argparse
from collections import Counter
from copy import deepcopy
import json


CONFIGURATION = {
    "purpose": "draft administrative replies for operator review",
    "data_classes": ["internal"],
    "code": "C1", "model": "M1", "prompt": "P1", "corpus": "D1",
    "policy": "POL1", "tools": ["read-guide", "draft-reply"],
}
# These dependencies describe the limited claim each fictional check covers.
# They are authored assumptions, not a discovered map of a real application.
CHECKS = {
    "tenant-boundary": {
        "claim": "The scoped lookup refused another workspace's record",
        "depends_on": ["code", "policy", "corpus"],
    },
    "supported-draft": {
        "claim": "The supplied sample's drafts used the permitted source",
        "depends_on": ["code", "model", "prompt", "corpus"],
    },
    "tool-denial": {
        "claim": "The dispatcher refused the supplied send proposal",
        "depends_on": ["code", "policy", "tools"],
    },
    "manual-fallback": {
        "claim": "The operator followed the supplied unavailable-source rehearsal",
        "depends_on": ["code", "policy"],
    },
}
CASES = ("unchanged", "model-change", "source-change", "tool-expansion",
         "missing-record", "failed-boundary", "reported-incident")


def make_packet(case):
    if case not in CASES:
        raise ValueError("Unknown teaching case")
    packet = {
        "configuration": deepcopy(CONFIGURATION),
        "reviewed_configuration": deepcopy(CONFIGURATION),
        "review_owner": "Fictional workflow owner",
        "records": {
            check_id: {
                "result": "pass", "origin": "supplied fictional observation",
                "basis": {key: deepcopy(CONFIGURATION[key]) for key in check["depends_on"]},
            } for check_id, check in CHECKS.items()
        },
        "incidents": [],
    }
    if case == "model-change":
        packet["configuration"]["model"] = "M2"
    elif case == "source-change":
        packet["configuration"]["corpus"] = "D2"
    elif case == "tool-expansion":
        packet["configuration"]["purpose"] = "create and send administrative tickets"
        packet["configuration"]["tools"].append("send-ticket")
    elif case == "missing-record":
        del packet["records"]["manual-fallback"]
    elif case == "failed-boundary":
        packet["records"]["tenant-boundary"]["result"] = "fail"
    elif case == "reported-incident":
        packet["incidents"].append({
            "id": "INC-01", "state": "reported; not investigated",
            "report": "An internal draft reportedly contained private contact details",
        })
    return packet


def changed_fields(before, after):
    return [key for key in sorted(set(before) | set(after))
            if key not in before or key not in after or before[key] != after[key]]


def inspect_packet(packet):
    results = []
    for check_id, check in CHECKS.items():
        record = packet["records"].get(check_id)
        if record is None:
            results.append({"check": check_id, "status": "missing", "changed_basis": []})
            continue
        if record["result"] not in ("pass", "fail", "not-run"):
            raise ValueError("Result must remain pass, fail or not-run")
        current = {key: packet["configuration"].get(key) for key in check["depends_on"]}
        changed = changed_fields(record["basis"], current)
        results.append({
            "check": check_id, "claim": check["claim"],
            "status": "stale" if changed else record["result"],
            "recorded_result": record["result"], "changed_basis": changed,
            "origin": record["origin"],
        })
    changed = changed_fields(packet["reviewed_configuration"], packet["configuration"])
    counts = Counter(result["status"] for result in results)
    return {
        "configuration": packet["configuration"],
        "changed_since_review": changed,
        "matches_recorded_configuration": not changed,
        "evidence": results,
        "counts": {status: counts[status] for status in ("pass", "stale", "missing", "fail", "not-run")},
        "incident_reports": packet["incidents"],
        "decision": "Not made by this program; take the findings and gaps to the responsible owner",
        "limits": "Compares supplied metadata only; does not execute controls, verify records, assess legal duties or authorize deployment",
    }


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("case", choices=["compare", *CASES], nargs="?", default="compare")
    args = parser.parse_args()
    cases = CASES if args.case == "compare" else (args.case,)
    print(json.dumps({
        "synthetic": True,
        "scope": "Original learning packets; no model, network, runtime policy or actual review is executed",
        "results": [{"case": case, **inspect_packet(make_packet(case))} for case in cases],
    }, indent=2))


if __name__ == "__main__":
    main()
