//! cuBLAS math-mode helper for the determinism foundation (spec §2.B + §4).
//!
//! Per `docs/superpowers/notes/2026-06-02-determinism-phase2.2-mamba2-investigation.md`:
//! the cuBLAS GEMM default algorithm (`CUBLAS_GEMM_DFALT`) permits split-K
//! accumulation with non-deterministic ordering on Ampere+ when TF32 mode
//! is on. The fix is to call `cublasSetMathMode(handle, CUBLAS_PEDANTIC_MATH)`
//! at every handle construction site — that filters out the non-deterministic
//! algorithm variants.
//!
//! Spec §4 dev/prod toggle: `FOXHUNT_DETERMINISTIC` env var (default "1" in
//! dev, where verdict trust matters; "0" in production, where the 10-15%
//! TF32 speed gain matters more than reproducibility).
//!
//! Call this immediately after `CudaBlas::new(...)` at every handle site
//! in `crates/ml-alpha/src/`. The 3 known sites (2026-06-02) are:
//!   - `mamba2_block.rs`        (Mamba2Block::new, line ~535)
//!   - `rl/dqn.rs`              (DqnHead::new, line ~364)
//!   - `rl/iqn.rs`              (IqnHead::new, line ~261)
//!
//! Per `feedback_isv_for_adaptive_bounds.md`: env-var read is one-shot at
//! handle construction; the mode is fixed for the lifetime of the handle.
//! No per-step ISV adjustment is needed (or possible, since the mode is
//! handle-level state).

use anyhow::{anyhow, Result};
use cudarc::cublas::CudaBlas;

/// Apply the dev/prod-toggleable cuBLAS math mode to a freshly-constructed
/// `CudaBlas` handle.
///
/// `FOXHUNT_DETERMINISTIC=1` (default) → `CUBLAS_PEDANTIC_MATH`. Deterministic
/// across runs; ~10-15% slower than TF32 on Ampere+ GEMMs.
///
/// `FOXHUNT_DETERMINISTIC=0` → `CUBLAS_TF32_TENSOR_OP_MATH`. Faster, but
/// `CUBLAS_GEMM_DFALT` may pick non-deterministic split-K variants — same-seed
/// runs can diverge by ~1e-6 after a handful of GEMMs, cascading via the
/// optimizer into ~10% trajectory drift over 200 steps.
///
/// Returns the input handle wrapped in `Ok` on success (passthrough for
/// ergonomic call-site chaining), or `Err` if the cuBLAS call fails.
pub fn apply_deterministic_math_mode(cublas: CudaBlas) -> Result<CudaBlas> {
    // Per `pearl_build_rs_rerun_if_env_changed.md`: this env-var read is a
    // runtime decision (not a build-time one), so no `cargo:rerun-if-env-changed`
    // is needed. The env var is checked once per handle construction.
    //
    // Phase 2.4 control-mode addition (2026-06-02): added `2` as control
    // mode (CUBLAS_DEFAULT_MATH — no TF32, no PEDANTIC, pure FP32) to
    // disambiguate whether PEDANTIC fully eliminates split-K or just
    // some variants. Per dispatch ask.
    let env_value = std::env::var("FOXHUNT_DETERMINISTIC")
        .unwrap_or_else(|_| "1".to_string());

    let mode = match env_value.as_str() {
        "0" => cudarc::cublas::sys::cublasMath_t::CUBLAS_TF32_TENSOR_OP_MATH,
        "2" => cudarc::cublas::sys::cublasMath_t::CUBLAS_DEFAULT_MATH,
        _ => cudarc::cublas::sys::cublasMath_t::CUBLAS_PEDANTIC_MATH,
    };

    unsafe {
        cudarc::cublas::sys::cublasSetMathMode(*cublas.handle(), mode)
            .result()
            .map_err(|e| anyhow!("cublasSetMathMode {mode:?}: {e:?}"))?;
    }

    // Print once per handle so callers can verify the env var propagated.
    // Phase 2.4: this is essential diagnostics — the Phase 2.3 outcome
    // note claimed PEDANTIC was active but later determinism-check runs
    // showed attn_q still diverging, so we need explicit confirmation.
    static MODE_PRINTED: std::sync::OnceLock<()> = std::sync::OnceLock::new();
    MODE_PRINTED.get_or_init(|| {
        eprintln!(
            "[cublas_determinism] FOXHUNT_DETERMINISTIC={env_value} → mode={mode:?}"
        );
    });

    Ok(cublas)
}
