"""Build pinned LMDB and run only disposable, bounded synthetic environments."""
import argparse
import hashlib
import json
import platform
import subprocess
import tempfile
from datetime import datetime, timezone
from pathlib import Path

COMMIT = "3a29a24777c82a0165de813ae696a5068b5add30"
HASHES = {
    "mdb.c": "2fd45dcef13f94ecc6650da19f341af38cceb53b9d3b88e854f621cc319dc1b1",
    "midl.c": "91110543f2e84c516188c1e3960b1f504e1c60a4766027a782349c000276ca93",
    "lmdb.h": "ea935082e5d5ea7ba685ee599c617f28353060710b0369d220a55f64bb07f1c2",
    "midl.h": "cef8236dc7dce9b5346d212d31e8330f9158bacabe270b14ab1e99745db118c6",
    "LICENSE": "310fe25c858a9515fc8c8d7d1f24a67c9496f84a91e0a0e41ea9975b1371e569",
}

def validate(rows):
    assert len(rows) == 18
    for size in (1048576, 2097152):
        selected = [r for r in rows if r["map_bytes"] == size]
        for mode in ("released", "pinned", "reset"):
            group = [r for r in selected if r["mode"] == mode]
            assert len(group) == 3 and group[0] == group[1] == group[2]
        pinned = next(r for r in selected if r["mode"] == "pinned")
        for row in selected:
            assert row["full_payload_oracle"] and row["map_unchanged"]
            assert row["post_release_updates"] == 64 and row["dead_readers_cleared"] == 0
            assert row["logical_value_bytes"] == 131072
            assert len(row["trace"]) == row["updates_committed"]
            assert row["trace"][-1][1] == row["before_release_high_water_bytes"]
            assert row["after_release_high_water_bytes"] < size
            if row["mode"] == "pinned":
                assert row["failure_rc"] == row["retry_after_reader_check_rc"] == -30792
                assert 0 < row["updates_committed"] < 256
                assert row["pinned_snapshot_unchanged"]
            else:
                assert row["failure_rc"] == 0 and row["updates_committed"] == 256
                assert row["before_release_high_water_bytes"] < pinned["before_release_high_water_bytes"]

def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--lmdb", required=True, type=Path, help="LMDB repository at the recorded commit")
    parser.add_argument("--output", required=True, type=Path)
    args = parser.parse_args()
    src = args.lmdb / "libraries/liblmdb"
    for name, expected in HASHES.items():
        assert hashlib.sha256((src / name).read_bytes()).hexdigest() == expected, name
    program = Path(__file__).with_name("lmdb-reader-lifetime.c")
    with tempfile.TemporaryDirectory(prefix="hesela-lmdb-build-") as temp:
        binary = Path(temp) / "observe"
        command = ["cc", "-O2", "-pthread", "-I", str(src), str(program),
                   str(src / "mdb.c"), str(src / "midl.c"), "-o", str(binary)]
        subprocess.run(command, check=True, timeout=90, capture_output=True)
        rows = []
        for _ in range(3):
            for size in (1048576, 2097152):
                for mode in ("released", "pinned", "reset"):
                    result = subprocess.run([str(binary), mode, str(size)], check=True,
                                            capture_output=True, text=True, timeout=30)
                    rows.append(json.loads(result.stdout))
    validate(rows)
    report = {
        "schemaVersion": 1, "generatedAt": datetime.now(timezone.utc).isoformat(),
        "evidenceType": "controlled-synthetic-runtime-observation",
        "lmdbVersion": "0.9.33", "sourceCommit": COMMIT,
        "sourceUrl": "https://github.com/LMDB/lmdb/tree/" + COMMIT,
        "sourceLicense": "OpenLDAP Public License 2.8; source not redistributed",
        "sourceHashes": HASHES, "harnessSha256": hashlib.sha256(program.read_bytes()).hexdigest(),
        "runnerSha256": hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),
        "environment": {"system": platform.system(), "release": platform.release(),
                        "machine": platform.machine(), "python": platform.python_version(),
                        "compiler": subprocess.check_output(["cc", "--version"], text=True).splitlines()[0]},
        "method": {"keys": 8, "valueBytes": 16384, "attemptedOverwrites": 256,
                   "postReleaseOverwrites": 64, "repetitions": 3, "seed": "none; deterministic",
                   "flags": ["MDB_NOTLS"], "durabilityFlagsDisabled": [],
                   "highWaterDefinition": "(me_last_pgno + 1) * ms_psize; not live bytes or allocated disk blocks"},
        "limits": ["One Linux environment and pinned build; not a benchmark or failure-rate sample.",
                   "Sequential API calls with overlapping transaction lifetimes; no concurrent processes.",
                   "No process death, hardware fault, power loss or storage durability test.",
                   "Exact counts depend on page size, map geometry, build and workload.",
                   "Map capacity is not free filesystem space; ending a reader is not file compaction."],
        "cases": rows,
    }
    args.output.parent.mkdir(parents=True, exist_ok=True)
    args.output.write_text(json.dumps(report, indent=2) + "\n")
    print(json.dumps({"cases": len(rows), "validated": True, "output": str(args.output)}))

if __name__ == "__main__":
    main()
