//! Timing-baseline gate for `mcptest run --check-baseline`.
//!
//! Pulled out of `run_live.rs` so the parent stays under the
//! production-module-size cap. The gate is small and pure
//! (load + check + render), so it lives here in isolation.

use anyhow::Result;

/// Compare the run report against a saved timing baseline. Returns
/// `true` when any test's elapsed milliseconds exceeded its
/// recorded p90 by more than `tolerance_pct`, mirroring how the
/// tool-selection floor and matrix-assert gates fold into the final
/// exit code. The no-baseline path is the legacy no-op and returns
/// `false`.
pub(super) fn gate_timing_baseline(
    report: &mcptest_core::report::Report,
    baseline_path: Option<&std::path::Path>,
    tolerance_pct: f64,
    quiet: bool,
) -> Result<bool> {
    let Some(path) = baseline_path else {
        return Ok(false);
    };
    let baseline = mcptest_core::baseline::load(path)
        .map_err(|e| anyhow::anyhow!("failed to load baseline `{}`: {e}", path.display()))?;
    let warnings = mcptest_core::baseline::check_against(&baseline, report, tolerance_pct)
        .map_err(|e| anyhow::anyhow!("baseline check failed: {e}"))?;
    if warnings.is_empty() {
        if !quiet {
            tracing::info!(
                target: "mcptest::baseline",
                baseline = %path.display(),
                "timing baseline check passed"
            );
        }
        return Ok(false);
    }
    if !quiet {
        eprintln!(
            "\n\x1b[1;33mtiming baseline regressions ({} test{}) vs {} (tolerance {:.1}%):\x1b[0m",
            warnings.len(),
            if warnings.len() == 1 { "" } else { "s" },
            path.display(),
            tolerance_pct,
        );
        for warning in &warnings {
            eprintln!(
                "  {} {:.0}ms vs baseline p90 {:.0}ms ({:.2}x)",
                warning.test_id, warning.actual_ms, warning.baseline_p90_ms, warning.ratio,
            );
        }
    }
    Ok(true)
}
