"""Independent upper-bound checker. Imports nothing from the solver or oracle
modules: it rebuilds P(n,5) from the definition, replays every stored
chronology in results/upper_bound_witnesses.jsonl force by force (checking
that the source is black, the target white, and the target is the unique
white neighbour of the source), and checks that the final set is V.
Also replays the uniform 12-vertex construction of P7 for 13 <= n <= NMAX.
Writes results/upper_bound_verification.json. Exit code 1 on any failure.
"""
import json
import os
import sys

ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
os.chdir(ROOT)


def petersen_adj(n, k):
    adj = {}
    for i in range(n):
        for a, b in ((("u", i), ("u", (i + 1) % n)), (("u", i), ("v", i)), (("v", i), ("v", (i + k) % n))):
            adj.setdefault(a, set()).add(b)
            adj.setdefault(b, set()).add(a)
    return adj


def parse(lbl):
    return (lbl[0], int(lbl[1:]))


def replay(adj, S, chron):
    black = set(S)
    for idx, (b, w) in enumerate(chron):
        if b not in black or w in black:
            return False, idx
        white = [x for x in adj[b] if x not in black]
        if white != [w]:
            return False, idx
        black.add(w)
    return len(black) == len(adj), None


def p7_chronology(n):
    S = [("u", i) for i in range(12)]
    ch = [(("u", i), ("v", i)) for i in range(1, 11)] + [(("v", 5), ("v", 0)), (("v", 6), ("v", 11))]
    for j in range(12, n):
        ch.append((("u", j - 1), ("u", j)))
        ch.append((("v", j - 5), ("v", j)))
    return S, ch


if __name__ == "__main__":
    nmax = int(sys.argv[1]) if len(sys.argv) > 1 else 60
    report = {"witnesses": [], "P7": []}
    ok_all = True
    path = "results/upper_bound_witnesses.jsonl"
    seen = set()
    if os.path.exists(path):
        for line in open(path):
            w = json.loads(line)
            n = w["n"]
            adj = petersen_adj(n, w["k"])
            S = [parse(s) for s in w["S"]]
            chron = [(parse(a), parse(b)) for a, b in w["chronology"]]
            ok, bad = replay(adj, S, chron)
            ok = ok and len(set(S)) == w["size"] == len(S)
            report["witnesses"].append({"n": n, "size": w["size"], "replay_ok": ok, "first_bad_force": bad, "source": w.get("source")})
            ok_all &= ok
    for n in range(13, nmax + 1):
        adj = petersen_adj(n, 5)
        S, ch = p7_chronology(n)
        ok, bad = replay(adj, S, ch)
        report["P7"].append({"n": n, "replay_ok": ok, "forces": len(ch)})
        ok_all &= ok
    # n = 12: outer layer then spokes
    adj = petersen_adj(12, 5)
    ok, bad = replay(adj, [("u", i) for i in range(12)], [(("u", i), ("v", i)) for i in range(12)])
    report["P7"].insert(0, {"n": 12, "replay_ok": ok, "forces": 12})
    ok_all &= ok
    report["all_ok"] = ok_all
    with open("results/upper_bound_verification.json", "w") as f:
        json.dump(report, f, indent=1)
    print("witness replays: %d, P7 replays: %d, all ok: %s" % (len(report["witnesses"]), len(report["P7"]), ok_all))
    sys.exit(0 if ok_all else 1)
