"""Positive controls for the actual analysis functions; never added to study samples."""
import hashlib
import json
import tempfile
from pathlib import Path

import numpy as np
from scipy import stats

from analyze import analyze, clopper_pearson, holm


def main():
    protocol = {"alpha": 0.01, "autocorrelationLags": 20}
    checks = []
    np.testing.assert_allclose(holm([0.01, 0.04, 0.03, 0.002]), [0.03, 0.06, 0.06, 0.008])
    checks.append("Holm: hand-computed step-down example")
    for count, n in [(0, 10), (10, 10), (49682, 1000000), (2494, 50000)]:
        expected = stats.binomtest(count, n).proportion_ci(confidence_level=0.95, method="exact")
        np.testing.assert_allclose(clopper_pearson(count, n), [expected.low, expected.high], atol=1e-11)
    checks.append("Clopper-Pearson: boundary and study cases match SciPy exact intervals")
    with tempfile.TemporaryDirectory() as directory:
        data = Path(directory)
        seeds = data / "control.seeds"
        seeds.write_bytes(bytes(16))
        def run(values):
            path = data / "control.u8"
            path.write_bytes(values.astype(np.uint8).tobytes())
            entry = {"id": "control", "environment": "synthetic", "mode": "control",
                     "algorithm": "none", "sides": 20, "outcomes": len(values),
                     "outcomesFile": path.name, "seedsFile": seeds.name,
                     "outcomesSha256": hashlib.sha256(path.read_bytes()).hexdigest(),
                     "seedsSha256": hashlib.sha256(seeds.read_bytes()).hexdigest()}
            return analyze(entry, data, protocol, 500)[0]
        # Exhaustive, balanced ordered pairs, rather than another random sample.
        balanced = np.tile(np.array([(i, j) for i in range(1, 21) for j in range(1, 21)]).flatten(), 100)
        record = run(balanced)
        assert record["chiSquare"] == 0 and record["pUniformity"] == 1
        assert record["serialChiSquare"] == 0 and record["pSerial"] == 1
        checks.append("Balanced exhaustive pairs: uniformity and independence statistics are zero")
        biased = balanced.copy()
        biased[np.flatnonzero(biased == 20)[::2]] = 1
        record = run(biased)
        assert record["pUniformity"] < 1e-50
        checks.append("Artificial face bias: actual uniformity analysis rejects")
        repeated = np.repeat(np.tile(np.arange(1, 21), 2000), 2)
        record = run(repeated)
        assert record["pUniformity"] == 1 and record["pSerial"] < 1e-50
        checks.append("Balanced marginals with repeated pairs: actual independence analysis rejects")
    for q, sides in [(256, 20), (256, 6), (65536, 100)]:
        limit = q // sides * sides
        counts = np.bincount(np.arange(limit) % sides, minlength=sides)
        assert np.all(counts == limit // sides)
    checks.append("Exhaustive toy rejection mapping: every accepted face has equal preimages")
    print(json.dumps({"passed": len(checks), "checks": checks}, indent=2))


if __name__ == "__main__":
    main()
