//! Verifies SoftReset dispatch writes bootstrap values that the existing
//! grad_balance_isv_update EMA converges from smoothly over subsequent
//! epochs. Task 4 (D.5) of Plan 2.
//!
//! These tests are CPU-only (no GPU, no fxcache) — they verify registry
//! classification and the Option A design invariants.

#[cfg(test)]
mod tests {
    use crate::trainers::dqn::state_reset_registry::{ResetCategory, StateResetRegistry};

    #[test]
    fn soft_reset_entries_classified_correctly() {
        let r = StateResetRegistry::new();
        assert_eq!(
            r.category("isv_grad_balance_targets"),
            Some(ResetCategory::SoftReset { decay_bars: 500 }),
            "isv_grad_balance_targets must be SoftReset{{decay_bars: 500}}"
        );
        assert_eq!(
            r.category("isv_grad_scale_limit"),
            Some(ResetCategory::SoftReset { decay_bars: 500 }),
            "isv_grad_scale_limit must be SoftReset{{decay_bars: 500}}"
        );
    }

    #[test]
    fn soft_reset_entries_are_non_empty() {
        let r = StateResetRegistry::new();
        let count = r.soft_reset_entries().count();
        assert!(
            count >= 2,
            "expected >= 2 SoftReset entries, got {count}"
        );
    }

    #[test]
    fn soft_reset_entries_not_in_fold_reset() {
        let r = StateResetRegistry::new();
        let fold_names: Vec<&str> = r.fold_reset_entries().map(|e| e.name).collect();
        assert!(
            !fold_names.contains(&"isv_grad_balance_targets"),
            "isv_grad_balance_targets must not appear in fold_reset_entries"
        );
        assert!(
            !fold_names.contains(&"isv_grad_scale_limit"),
            "isv_grad_scale_limit must not appear in fold_reset_entries"
        );
    }

    /// Verify the bootstrap constants match the values written at construction
    /// in gpu_dqn_trainer.rs (lines 8357-8360). If these diverge the fold-
    /// boundary reset would write a different value than the initial state,
    /// which would be a latent bug.
    #[test]
    fn bootstrap_values_match_construction_constants() {
        // grad_norm target bootstrap = 1.0 (neutral, no scaling before first EMA update)
        let target_bootstrap: f32 = 1.0;
        // scale_limit bootstrap = 2.0 (allows up to 2× rescaling before EMA grows)
        let limit_bootstrap: f32 = 2.0;

        assert!(
            target_bootstrap > 0.0,
            "target bootstrap must be positive so EMA starts from a valid scale"
        );
        assert!(
            limit_bootstrap >= 2.0,
            "limit bootstrap must be >= 2.0 (kernel hard-floor in grad_balance_isv_update)"
        );
    }
}
