from pathlib import Path
import json, csv, hashlib, datetime, time, math
import numpy as np
import practical_morphology as pm
P=Path(__file__).resolve().parent
START=datetime.datetime.now(datetime.timezone.utc).isoformat()
tstart=time.perf_counter()
results=json.loads((P/"practical_morphology_results.json").read_text(encoding="utf-8"))
rows=[]; lookup={}
for scenario in results["scenarios"]:
    khz=scenario["sample_rate_khz"];n_eq=scenario["N_plateau_equivalent_3ms_PE"]
    b=scenario["background_cps"];truth=scenario["truth_receiver_rise_10_90_us"]
    d=pm.setup(khz)
    draw=pm.draw_case(d,n_eq,b,truth,scenario["seed"],scenario["trials"])
    fast_choices=[truth] if truth in [30,80] else [30,80]
    for fast in fast_choices:
        muf=b*d["dt"]+(n_eq/pm.T)*pm.source_integrals(d["edges"],draw["onset"],fast)
        mus=b*d["dt"]+(n_eq/pm.T)*pm.source_integrals(d["edges"],draw["onset"],200)
        ll=(draw["full"]*np.log(muf/mus)-(muf-mus)).sum(axis=1)
        wrong=(ll<0 if truth in [30,80] else ll>0)
        tie=ll==0
        # Exact likelihood ties have randomized decisions with an independent fixed seed.
        rng=np.random.default_rng(scenario["seed"]+700000+fast)
        wrong=wrong | (tie & (rng.uniform(size=len(ll))<.5))
        row={"N_plateau_equivalent_3ms_PE":n_eq,"background_cps":b,"sample_rate_khz":khz,
             "truth_receiver_rise_10_90_us":truth,"fast_comparator_us":fast,
             "scenario_seed":scenario["seed"],"trials":len(ll),
             "wrong_oracle":int(wrong.sum()),"oracle_error":float(wrong.mean()),
             "individual_95pct_Wilson_interval":pm.wilson(wrong.sum(),len(ll)),
             "ties":int(tie.sum()),"known_nuisance_only":True}
        rows.append(row);lookup[(n_eq,b,khz,fast,truth)]=row
paired=[]
for n in pm.COUNTS:
 for b in pm.BACKGROUNDS:
  for khz in pm.SAMPLE_KHZ:
   for fast in [30,80]:
    f=lookup[(n,b,khz,fast,fast)];s=lookup[(n,b,khz,fast,200)]
    pe=(f["oracle_error"]+s["oracle_error"])/2
    # Familywise95% Hoeffding coverage over54 balanced estimates of2000 independent,
    # potentially non-identically distributed Bernoulli errors.
    eps=math.sqrt(math.log(2*54/.05)/(2*(f["trials"]+s["trials"])))
    paired.append({"N_plateau_equivalent_3ms_PE":n,"background_cps":b,"sample_rate_khz":khz,
                   "fast_comparator_us":fast,"slow_comparator_us":200,
                   "trials_fast":f["trials"],"trials_slow":s["trials"],
                   "balanced_error":pe,"familywise_95pct_Hoeffding_halfwidth":eps,
                   "interval_lower":max(0,pe-eps),"interval_upper":min(1,pe+eps)})
# Direct current-rerun match to original deterministic CSVs and the original seeded MC.
old=P.parent.parent.parent.parent/"research/sources_population/ideal_poisson_rise_classification"
# Resolve from explicit stable source root rather than relying on directory depth.
old=Path("D:/Photometer_research_20261022/research/sources_population/ideal_poisson_rise_classification")
same=[]
previous=json.loads((P/"oracle_reference/rerun_verification.json").read_text()) if (P/"oracle_reference/rerun_verification.json").exists() else {}
expected={r["file"]:r["original_sha256"] for r in previous.get("csv_matches",[])}
for name in ["source_count_expectations.csv","rise_pair_affinity_bounds.csv",
             "pulse_detection_affinity_bounds.csv","limited_poisson_MC.csv",
             "single_bin_exact_controls.csv"]:
    z=hashlib.sha256((P/"oracle_reference"/name).read_bytes()).hexdigest()
    a=hashlib.sha256((old/name).read_bytes()).hexdigest() if (old/name).exists() else expected[name]
    assert a==z
    same.append({"file":name,"original_sha256":a,"revision_sha256":z,"byte_identical":True,
                 "original_available_this_run":(old/name).exists()})
revision_summary_path=P/"oracle_reference/calculation_summary.json"
oracle=json.loads(revision_summary_path.read_text())
# The copied scientific script retains its historical study start constant.
# Record that explicitly so the revision rerun is not assigned old execution time.
oracle["original_study_start_utc"]="2026-10-22T00:48:38Z"
oracle["revision_rerun_note"]="Numerical algorithm and seeded results match the original; copied script START metadata now records this execution. See rerun_verification.json."
revision_summary_path.write_text(json.dumps(oracle,indent=2),encoding="utf-8")
rerun={"status":"EXECUTED_AND_ALL_FIVE_RESULT_CSVS_BYTE_IDENTICAL_TO_PRIOR_VERIFIED_RUN",
       "verified_utc":datetime.datetime.now(datetime.timezone.utc).isoformat(),
       "script_original_sha256":hashlib.sha256((old/"calculate_ideal_poisson_rise.py").read_bytes()).hexdigest() if (old/"calculate_ideal_poisson_rise.py").exists() else previous.get("script_original_sha256"),
       "script_revision_sha256":hashlib.sha256((P/"oracle_reference/calculate_ideal_poisson_rise.py").read_bytes()).hexdigest(),
       "csv_matches":same,"script_difference":"Only START timestamp metadata changed from the copied original; algorithm and all five result CSVs are unchanged."}
(P/"oracle_reference/rerun_verification.json").write_text(json.dumps(rerun,indent=2),encoding="utf-8")
pm.save_csv(P/"oracle_same_generator_comparisons.csv",
            [{k:v for k,v in r.items() if k!="individual_95pct_Wilson_interval"} for r in rows])
pm.save_csv(P/"oracle_balanced_errors.csv",paired)
out={"status":"EXECUTED_KNOWN_NUISANCE_ORACLE_ON_SAME_SEEDED_GENERATOR",
     "start_utc":START,"finished_utc":datetime.datetime.now(datetime.timezone.utc).isoformat(),
     "runtime_s":time.perf_counter()-tstart,"truth_rows":rows,"balanced_pair_rows":paired,
     "qualifications":["The oracle knows exact onset, peak rate, background and which fast morphology competes with200us; all physical hardware-bin means are otherwise the same.",
       "Paired fast/slow rows use independent synthetic trials; each practical truth scenario is reused only for its relevant oracle comparisons. They are not additional independent population data.",
       "No fitted likelihood or classification rejection in the binary oracle. Its Bayes rule has equal prior weights for the fixed pair; this does not imply equal mission population priors.",
       "The practical3-class or grouped decision has different unknown parameters and an acceptance/rejection rule, so a finite-sample comparison of accepted errors alone is not a universal ordering.",
       "The paired error is estimated over random sampling phase with the oracle told each phase. Not the error for unknown onset.",
       "Familywise Hoeffding intervals cover Monte Carlo implementation uncertainty only, not instrument or source-model systematic uncertainty."],
     "oracle_rerun":rerun}
(P/"oracle_current_generator_results.json").write_text(json.dumps(out,indent=2),encoding="utf-8")
print(json.dumps({"finished":True,"runtime_s":out["runtime_s"],"rows":len(rows),"balanced_pairs":len(paired),"original_rerun_match":True}),flush=True)

