"""The status registry: every status phrase the corpus uses in a judgment
position (the census, RUN-003), and - filled in round by round as this tree
reads the corpus - what the corpus says each phrase means, and how each
judgment is actually known.

known_by: analytic | theorem-application | computation | reading |
          outside-corpus | n/a
verdict:  PASS | PASS by cited theorem | PARTIAL | UNMEASURED | FAIL | n/a
"""
import json

from corpus import TREE

REGISTRY = TREE / "data" / "STATUS_REGISTRY.v1.json"
# census v5 found judgments in rounds already read; their reviews live in one table
# (see its note) and join each round's own here
SUPPLEMENT = TREE / "data" / "STATUS_REVIEWS.census-v5.json"
KNOWN_BY = {"analytic", "theorem-application", "computation", "reading", "outside-corpus", "n/a"}
VERDICTS = {"PASS", "PASS by cited theorem", "PARTIAL", "UNMEASURED", "FAIL", "n/a"}


def load():
    return json.loads(REGISTRY.read_text(encoding="utf-8"))


def supplement(round_id, run_id=None):
    """the census-v5 definitions and reviews for a round already read"""
    rows = json.loads(SUPPLEMENT.read_text(encoding="utf-8")).get(round_id, {}) if SUPPLEMENT.exists() else {}
    if run_id and rows and rows["run"] != run_id:
        raise ValueError(f"{round_id}'s census-v5 rows belong to {rows['run']}, not {run_id}")
    return ({p: tuple(d) for p, d in rows.get("definitions", {}).items()},
            [tuple(r) for r in rows.get("reviews", [])])


def completeness(registry, round_id, definitions, reviews):
    """Failures: a judgment of the round without exactly one review, a review
    matching no judgment, a phrase first used in the round without a
    definition, or a review outside the fixed vocabularies."""
    more_definitions, more_reviews = supplement(round_id)
    definitions = {**definitions, **more_definitions}
    reviews = list(reviews) + more_reviews
    st = registry["statuses"]
    occ = [(s, o[2]) for s, v in st.items() for o in v["occurrences"] if o[0] == round_id]
    got = [(r[0], r[1]) for r in reviews]
    out = []
    for key in sorted(set(occ) | set(got)):
        a, b = occ.count(key), got.count(key)
        if b != a:
            out.append(f"{key[0]} / {key[1][:40]}: {a} judgment(s), {b} review(s)")
    for s, v in st.items():
        if v["first"] == round_id and s not in definitions:
            out.append(f"{s}: first used in {round_id}, no definition recorded")
    for s in definitions:
        if s not in st:
            out.append(f"{s}: defined but not in the census")
    for r in reviews:
        if r[2] not in KNOWN_BY or r[3] not in VERDICTS:
            out.append(f"{r[0]} / {r[1][:40]}: bad classification {r[2]!r} {r[3]!r}")
    return out


def record(round_id, run_id, definitions, reviews):
    more_definitions, more_reviews = supplement(round_id, run_id)
    reg = load()
    st = reg["statuses"]
    for phrase, (kind, text) in definitions.items():
        st[phrase]["definition"] = {"round": round_id, "run": run_id, "kind": kind, "text": text}
    for phrase, (kind, text) in more_definitions.items():
        st[phrase]["definition"] = {"round": round_id, "run": run_id, "kind": kind, "text": text,
                                    "added_by": "census v5"}
    rows = [(r, None) for r in reviews] + [(r, "census v5") for r in more_reviews]
    # clear the round's old rows first: a round may judge one subject more than once,
    # and each judgment keeps its own review (until 2026-09-25 only the last was kept)
    for status, subject in {(r[0], r[1]) for r, _ in rows}:
        st[status]["reviews"] = [x for x in st[status].get("reviews", [])
                                 if not (x["where"] == round_id and x["subject"] == subject)]
    for (status, subject, known_by, verdict, note), added in rows:
        row = {"where": round_id, "subject": subject, "known_by": known_by,
               "verdict": verdict, "note": note, "run": run_id}
        if added:
            row["added_by"] = added
        st[status].setdefault("reviews", []).append(row)
    REGISTRY.write_text(json.dumps(reg, ensure_ascii=False, indent=1) + "\n", encoding="utf-8")
