"""Synthetic numeric-guard replay; no game engine or compiled map is run.

Usage: python plane-probe.py /path/to/doomformer-checkout
"""
import hashlib
import importlib
import itertools
from pathlib import Path
import platform
import sys
import types

import numpy as np

PIN = "9d3acae475b6f3c2351ae7d1b6eb0c323796ffbd"
root = Path(sys.argv[1]).resolve() / "doomformer"
hashes = {
    "acc.py": "7c04e2cbba9030d5fddd361f44eec1a88f864b11337c23e3cce5f22ade3a140a",
    "intref.py": "7a046985ecdf171b359f2b00af2db64631270a0e1363a8c2d9f877374aa884c0",
    "planes.py": "a839fe184b76100deec91c749d24d961ab6b80942e84d4a33fd1e6fb19aa39b3",
    "shipped.py": "2df97fc94ecfa372cb79198898e61a32c67ba1067354468914301dc617e07333",
    "tile.py": "1b8447bd09f8d8ed19bdefe9f90de063e3a58627df49f3c5fbead8bef6761e02",
    "udmf.py": "3331eddaa9d69acd593d7b338effa29f0351d221c83da4a105b4b431d113042d",
}
for name, digest in hashes.items():
    assert hashlib.sha256((root / name).read_bytes()).hexdigest() == digest, name
# Bypass the public initializer, which loads the complete toolkit. The six
# original modules below import normally; no implementation is replaced.
package = types.ModuleType("doomformer")
package.__path__ = [str(root)]
sys.modules["doomformer"] = package
p = importlib.import_module("doomformer.planes")
ref = importlib.import_module("doomformer.intref")
print(f"Python {platform.python_version()}; NumPy {np.__version__}; source {PIN}")
print(f"PLANE_MAX={p.PLANE_MAX}; start=[{p.START_MIN},{p.START_MAX}]")

def ordered_peaks(bias, terms):
    """Independent event replay: record endpoints and starts by move direction."""
    endpoint = start = 0
    for order in itertools.permutations(terms):
        current = int(bias)
        for delta in order:
            if delta > 0:
                start = max(start, current)
            elif delta < 0:
                start = max(start, -current)
            current += int(delta)
            if delta > 0:
                endpoint = max(endpoint, current)
            elif delta < 0:
                endpoint = max(endpoint, -current)
    return endpoint, start

for bias, terms in [(14000, [100, -100]), (14000, [10, 10, -10, -10]),
                    (15000, [-2000]), (16001, [-2000])]:
    endpoint, start = ordered_peaks(bias, terms)
    peak = p.terms_peak(bias, terms)
    assert peak == endpoint
    print(f"bias={bias}; terms={terms}; final={bias + sum(terms)}; "
          f"bound={peak}; directional_start={start}; "
          f"move_rejected={peak > p.PLANE_MAX}; start_rejected={bool(p.start_errors('fixture', bias))}")

checked = 0
for terms in itertools.product([-3, -1, 0, 1, 3], repeat=4):
    for bias in [-15000, -14018, -1, 0, 1, 14018, 16000]:
        endpoint, _ = ordered_peaks(bias, terms)
        assert p.terms_peak(bias, terms) == endpoint, (bias, terms)
        checked += 1
assert checked == 4375
print(f"ordered_endpoint_oracle: {checked} fixtures passed (all 24 orderings each)")

# Shape-only fixture for mlp_static_peaks; this is not a validated or compiled
# full model. The first hidden pair cannot both activate for the same input.
net = types.SimpleNamespace(
    n_in=1, n_layers=3, signed_input=True,
    weights=[np.array([[1], [-1]]), np.array([[255, 255]]), np.array([[1]])],
    biases=[np.array([0, 0]), np.array([13550]), np.array([0])],
    thresholds=[np.array([1]), np.array([1]), np.array([1])],
)
static = dict(p.mlp_static_peaks(net))
actual = []
for x in [-1, 0, 1]:
    h = ref.adc_relu(net.weights[0] @ np.array([x]), net.thresholds[1])
    actual.append(p.terms_peak(net.biases[1], net.weights[1] * h))
assert static['-h2'] == 14060 and max(actual) == 13805
print(f"correlated_hidden_fixture: static_h2={static['-h2']}; "
      f"exhaustive_input_peak={max(actual)}; inputs={len(actual)}")
assert p.terms_peak(14000, [18]) == p.PLANE_MAX
assert p.terms_peak(14000, [19]) == p.PLANE_MAX + 1
assert not p.start_errors('fixture', [-15000, 16000])
assert p.start_errors('fixture', [-15001])
assert p.start_errors('fixture', [16001])
print("bound_edges: 14018 accepted by move predicate; 14019 rejected; start edges checked")
print("PASS: numeric guards only; no ViZDoom, ACC invocation, map compilation, or engine result")
