#!/usr/bin/env python3
"""Precompute mpmath high-precision O3 vectors for engineering.uncertainty.type_a.

Independent of Node/V8 binary64 and of the IUT. Tabulated fields are mean,
sample s, and u_A = s/√n. Not GUM combination and not Monte Carlo.

80 dps, round-to-nearest binary64. Does not pin a gmpy2 backend.

Re-run: python3 scripts/lib/cvp/oracles/generate-type-a-o3.py
"""
from __future__ import annotations

import json
import math
import shutil
from pathlib import Path

import mpmath as mp

DPS = 80
GENERATOR_ID = "type-a-mpmath-o3"
GENERATOR_VERSION = "1.0.0"
SEED = "20260916.type-a-o3"


def f64(x: mp.mpf) -> float:
    return float(x)


def type_a(values, ddof=1) -> dict:
    xs = [mp.mpf(v) for v in values]
    n = len(xs)
    mean = sum(xs) / n
    sse = sum((x - mean) ** 2 for x in xs)
    var = sse / (n - ddof)
    std = mp.sqrt(var)
    u_a = std / mp.sqrt(n)
    return {
        "mean_f64": f64(mean),
        "mean_decimal": mp.nstr(mean, 40, strip_zeros=False),
        "std_f64": f64(std),
        "std_decimal": mp.nstr(std, 40, strip_zeros=False),
        "u_A_f64": f64(u_a),
        "u_A_decimal": mp.nstr(u_a, 40, strip_zeros=False),
    }


def row(vid: str, inputs: dict, extra: dict, *, kind: str) -> dict:
    return {"id": vid, "kind": kind, "inputs": inputs, **extra}


def vectors() -> list[dict]:
    return [
        row("o3-123", {"values": [1, 2, 3], "ddof": 1}, type_a([1, 2, 3], 1), kind="bessel"),
        row("o3-ddof0", {"values": [1, 2, 3], "ddof": 0}, type_a([1, 2, 3], 0), kind="population"),
        row("o3-scale", {"values": [10, 20, 30], "ddof": 1}, type_a([10, 20, 30], 1), kind="scale"),
        row("o3-const", {"values": [5, 5, 5], "ddof": 1}, type_a([5, 5, 5], 1), kind="constant"),
        row("o3-two", {"values": [3, 7], "ddof": 1}, type_a([3, 7], 1), kind="two-point"),
        row("o3-five", {"values": [1, 2, 3, 4, 5], "ddof": 1}, type_a([1, 2, 3, 4, 5], 1), kind="n5"),
        row(
            "o3-neg",
            {"values": [-2, -1, 0, 1, 2], "ddof": 1},
            type_a([-2, -1, 0, 1, 2], 1),
            kind="centered",
        ),
        row("o3-default-ddof", {"values": [1, 2, 3]}, type_a([1, 2, 3], 1), kind="default-ddof"),
    ]


def main() -> None:
    mp.mp.dps = DPS
    here = Path(__file__).resolve().parent
    table = {
        "family": "type_a_uncertainty",
        "generator_id": GENERATOR_ID,
        "generator_version": GENERATOR_VERSION,
        "seed": SEED,
        "mpmath_dps": DPS,
        "precision_bits": int(DPS * math.log2(10)),
        "library": f"mpmath {mp.__version__}",
        "notes": "Type A mean/s/u_A only. Independent of Node Math and the IUT.",
        "vectors": vectors(),
    }
    dest = here / "type-a-o3-tables.json"
    dest.write_text(json.dumps(table, indent=2) + "\n", encoding="utf-8")
    public = here.parents[3] / "public/developers/cvp/reproduce"
    public.mkdir(parents=True, exist_ok=True)
    shutil.copy2(dest, public / "type-a-o3-tables.json")
    shutil.copy2(Path(__file__), public / "generate-type-a-o3.py")
    print(f"wrote {dest} ({len(table['vectors'])} vectors)")


if __name__ == "__main__":
    main()
