"""A precision control for the quadrupole in Mercury's radial cells.

The frozen production solver remains unchanged. This diagnostic cancels the
analytic Newtonian background before summing fluxes and tightens tolerances.
"""
import hashlib
import json
import subprocess
from dark_cmc_model import BASE, OUT, CMCResponse, candidate, digest
from build_cmc_solver import build
from dark_cmc_solar_checks import inner_profile


def main():
    _,build_record=build()
    source=(OUT/"solver/cmc_solar.rs").read_text()
    replacements=[
        ("let frh = mrh *", "let frh = (mrh - 1.) *"),
        ("let frl = mrl *", "let frl = (mrl - 1.) *"),
        ("let fuh = (1. - uhi * uhi) * muh *", "let fuh = (1. - uhi * uhi) * (if j + 1 < g.nu { muh - 1. } else { 0. }) *"),
        ("let ful = (1. - ulo * ulo) * mul *", "let ful = (1. - ulo * ulo) * (if j > 0 { mul - 1. } else { 0. }) *"),
        ("pcg(&op, &mut solved, 2e-11)","pcg(&op, &mut solved, 1e-15)"),
        ("delta < 2e-10 && nonlinear_error < 2e-9", "delta < 2e-14 && nonlinear_error < 2e-13")]
    for before,after in replacements:
        assert source.count(before)==1,before
        source=source.replace(before,after)
    source+='''
#[cfg(test)]
mod precise_background_test {
    use super::*;
    #[test]
    fn newton_background_is_exactly_zero_at_mercury() {
        let response=Response::new(Model::Newton, 0.);
        let grid=Grid::new(512,384,1e-5,40.,1.5,&response);
        let operator=assemble(&grid,&response,&vec![0.;512*384]);
        assert!(operator.rhs.iter().all(|x| *x == 0.));
    }
}
'''
    folder=OUT/"inner_solver"
    folder.mkdir(exist_ok=True)
    path=folder/"solar.rs"
    source_hash=hashlib.sha256(source.encode()).hexdigest()
    binary=folder/"solar"
    if not path.exists() or digest(path)!=source_hash or not binary.exists():
        path.write_text(source)
        subprocess.run(["rustc","--edition=2024","-O",str(path),"-o",str(binary)],check=True)
    tests=folder/"tests"
    subprocess.run(["rustc","--edition=2024","--test",str(path),"-o",str(tests)],check=True)
    tested=subprocess.run([str(tests)],capture_output=True,text=True)
    (folder/"tests.log").write_text(tested.stdout+tested.stderr)
    assert tested.returncode==0,tested.stdout+tested.stderr
    control=json.loads((OUT/"controls_summary.json").read_text())
    previous=next(row["solar"] for row in control["cases"] if row["solar"]["spec"]["rmin"]==1e-5)
    assert previous["spec"]["source_sha256"]==digest(BASE/"dark_cmc_model.py")
    settings={key:previous["spec"][key] for key in ["nr","nu","rmin","rmax","external","scale"]}
    settings["table_sha256"]=previous["table_sha256"]
    code=hashlib.sha256(json.dumps({"generated_source_sha256":source_hash,**settings},sort_keys=True).encode()).hexdigest()[:16]
    prefix=folder/f"field_{code}"
    if not prefix.with_suffix(".json").exists():
        command=[binary,"table",512,384,1e-5,40.,2.32e-10,prefix,0.,BASE/previous["table"],
                 candidate(CMCResponse())["galaxy_scale_m_s2"],1.]
        run=subprocess.run(list(map(str,command)),capture_output=True,text=True)
        prefix.with_suffix(".log").write_text(run.stdout+run.stderr)
        assert prefix.with_suffix(".json").exists(),run.stderr
    result=json.loads(prefix.with_suffix(".json").read_text())
    # A precision diagnostic must retain an unmet stopping target. Do not
    # relabel the numerical roundoff plateau as convergence to that target.
    assert result["nr"]==settings["nr"] and result["rmin"]==settings["rmin"]
    assert result["model_scale_m_s2"]==settings["scale"]
    field={"spec":previous["spec"],"field":str(prefix.with_suffix(".csv").relative_to(BASE))}
    diagnostic=inner_profile(field)
    reference=result["Q2_s_minus2"][0]
    inner=next(row for row in diagnostic["shells"] if row["radius_interval_au"]==[.3,.5])
    discrepancy=max(abs(inner[key]-reference) for key in ["minimum_Q2_from_shell_s_minus2","maximum_Q2_from_shell_s_minus2"])
    report={"source_sha256":digest(__file__),"base_solver":build_record,
        "control_changes":"Cancel the analytically zero background flux before summation; PCG 1e-15, iteration change 2e-14, nonlinear residual 2e-13",
        "generated_source_sha256":source_hash,"tests_log_sha256":digest(folder/"tests.log"),
        "physical_settings":settings,
        "requested_stopping_target_met":result["converged"],
        "termination_scope":"The strict potential-change target is below the observed floating-point plateau; the resulting field is retained as a precision diagnostic, not a certified converged solve",
        "result":result,"diagnostic":diagnostic,
        "maximum_mercury_shell_discrepancy_from_first_inner_fit_s_minus2":discrepancy,
        "mercury_cells_resolve_inner_quadrupole_within_20_percent":bool(discrepancy<.2*abs(reference)),
        "production_control_Q2_s_minus2":previous["result"]["Q2_s_minus2"][1],
        "change_from_production_middle_Q2_s_minus2":result["Q2_s_minus2"][1]-previous["result"]["Q2_s_minus2"][1],
        "field":field["field"],"field_sha256":digest(prefix.with_suffix(".csv")),
        "scope":__doc__.strip(),"input_sha256":{name:digest(BASE/name) for name in [
            "dark_cmc_model.py","dark_cmc_solar_checks.py","build_cmc_solver.py","outputs/dark_cmc/controls_summary.json"]}}
    (OUT/"inner_summary.json").write_text(json.dumps(report,indent=2,allow_nan=False)+"\n")
    print(json.dumps(report,indent=2),flush=True)


if __name__=="__main__":
    main()
