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

Independent of Node/V8 binary64 and of the IUT. Tabulated fields are
Cp, Cpk, Cpu, Cpl. Not Pp/Ppk, not Cpm, not P/T, not Monte Carlo.

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

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

import json
import math
import shutil
from pathlib import Path

import mpmath as mp

DPS = 80
GENERATOR_ID = "process-capability-mpmath-o3"
GENERATOR_VERSION = "1.0.0"
SEED = "20260916.process-capability-o3"


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


def indices(lsl, usl, mu, sigma) -> dict:
    lsl = mp.mpf(lsl)
    usl = mp.mpf(usl)
    mu = mp.mpf(mu)
    sigma = mp.mpf(sigma)
    Cp = (usl - lsl) / (6 * sigma)
    Cpu = (usl - mu) / (3 * sigma)
    Cpl = (mu - lsl) / (3 * sigma)
    Cpk = mp.mpf(min(Cpu, Cpl))
    return {
        "Cp_f64": f64(Cp),
        "Cp_decimal": mp.nstr(Cp, 40, strip_zeros=False),
        "Cpk_f64": f64(Cpk),
        "Cpk_decimal": mp.nstr(Cpk, 40, strip_zeros=False),
        "Cpu_f64": f64(Cpu),
        "Cpu_decimal": mp.nstr(Cpu, 40, strip_zeros=False),
        "Cpl_f64": f64(Cpl),
        "Cpl_decimal": mp.nstr(Cpl, 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-center", {"lsl": 0, "usl": 12, "mu": 6, "sigma": 1}, indices(0, 12, 6, 1), kind="centered"),
        row("o3-shift", {"lsl": 0, "usl": 12, "mu": 8, "sigma": 1}, indices(0, 12, 8, 1), kind="off-center-high"),
        row("o3-shift-low", {"lsl": 0, "usl": 12, "mu": 4, "sigma": 1}, indices(0, 12, 4, 1), kind="off-center-low"),
        row("o3-sigma2", {"lsl": 0, "usl": 12, "mu": 6, "sigma": 2}, indices(0, 12, 6, 2), kind="centered-wider"),
        row("o3-unit", {"lsl": 10, "usl": 16, "mu": 13, "sigma": 1}, indices(10, 16, 13, 1), kind="shifted-limits"),
        row("o3-neg", {"lsl": 0, "usl": 12, "mu": 14, "sigma": 1}, indices(0, 12, 14, 1), kind="negative-cpk"),
        row(
            "o3-alias",
            {"LSL": 0, "USL": 12, "mean": 6, "std": 1},
            indices(0, 12, 6, 1),
            kind="alias",
        ),
        row("o3-tight", {"lsl": 0, "usl": 6, "mu": 3, "sigma": 0.5}, indices(0, 6, 3, "0.5"), kind="tight"),
    ]


def main() -> None:
    mp.mp.dps = DPS
    here = Path(__file__).resolve().parent
    table = {
        "family": "process_capability",
        "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": "Design-stage Cp/Cpk only. Independent of Node Math and the IUT. P/T and Cpm are not tabulated.",
        "vectors": vectors(),
    }
    dest = here / "process-capability-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 / "process-capability-o3-tables.json")
    shutil.copy2(Path(__file__), public / "generate-process-capability-o3.py")
    print(f"wrote {dest} ({len(table['vectors'])} vectors)")


if __name__ == "__main__":
    main()
