#!/usr/bin/env python3
"""Exact teaching model, not a journal parser or a freshness oracle."""
import itertools
import json
from collections import Counter


def compare(a, b, bits=32):
    """Return the serial relation of a to b; no history bound is inferred."""
    if type(bits) is not int or not 2 <= bits <= 64:
        raise ValueError("bits must be an integer from 2 through 64")
    modulus = 1 << bits
    if any(type(x) is not int or not 0 <= x < modulus for x in (a, b)):
        raise ValueError("serials must be integers in the declared unsigned range")
    delta = (b - a) % modulus
    if delta == 0:
        return "equal"
    if delta == modulus // 2:
        return "ambiguous"
    return "older" if delta < modulus // 2 else "newer"


def fold_newest(values, bits=8):
    if not values:
        raise ValueError("at least one serial is required")
    winner = values[0]
    compare(winner, winner, bits)
    for value in values[1:]:
        relation = compare(winner, value, bits)
        if relation == "ambiguous":
            raise ValueError("half-range ambiguity")
        if relation == "older":
            winner = value
    return winner


def results():
    counts = Counter()
    disagreements = 0
    for a, b in itertools.product(range(256), repeat=2):
        relation = compare(a, b, 8)
        counts[relation] += 1
        if relation != "ambiguous" and ((a < b) != (relation == "older")):
            disagreements += 1
    inputs = [
        ("equal", 3, 3),
        ("adjacent", 3, 4),
        ("across wrap", 4294967294, 3),
        ("just below half", 3, 2147483650),
        ("exactly half", 3, 2147483651),
        ("beyond half", 3, 2147483652),
        ("cycle edge 1", 3, 1431655768),
        ("cycle edge 2", 1431655768, 2863311533),
        ("cycle edge 3", 2863311533, 3),
    ]
    return {
        "schemaVersion": 1,
        "evidenceType": "deterministic arithmetic demonstration",
        "scope": "Full 8-bit serial space; selected 32-bit inputs; no storage I/O.",
        "enumeration": {"bits": 8, "orderedPairs": 65536,
                        "relations": dict(sorted(counts.items())),
                        "unsignedDisagreementsOnDefinedPairs": disagreements,
                        "definedPairs": 65536 - counts["ambiguous"]},
        "boundaryCases": [
            {"case": label, "a": a, "b": b, "aRelativeToB": compare(a, b)}
            for label, a, b in inputs
        ],
        "cycle": {"bits": 8, "values": [0, 100, 200],
                  "permutationFolds": [
                      {"input": list(p), "selected": fold_newest(p)}
                      for p in itertools.permutations([0, 100, 200])
                  ]},
        "epochExample": {"old": {"epoch": 7, "counter": 42},
                         "new": {"epoch": 8, "counter": 42},
                         "lowCounterRelation": compare(42, 42),
                         "trustedFullValueRelation": "older"},
        "limits": [
            "Pair counts are exact enumeration, not probabilities of real failures.",
            "The model cannot establish that observed history fits in a half-range.",
            "Epoch comparison requires a trusted shared identity and epoch history.",
            "No database, filesystem recovery path, device or power loss was tested."
        ]
    }


if __name__ == "__main__":
    print(json.dumps(results(), indent=2, sort_keys=True))
