//! OSS scorer adapters and the startup registry builder.
//!
//! Why this module exists: `mcptest-scorer-core` ships the
//! [`mcptest_scorer_core::ScorerAdapter`] trait and the substrate, but it
//! stays transport-free, so it does not spawn subprocesses. The OSS `exec`
//! scorer, which shells out to an external wrapper, lives here in the
//! binary where `tokio::process` already pulls in. [`build_registry`] is the
//! one place the OSS binary registers its scorers; the enterprise binary
//! registers vendor adapters into the same registry shape at its own init.

pub mod config;
pub mod exec;

use std::sync::Arc;

use mcptest_scorer_core::{ScorerRegistry, TelemetrySink};

pub use config::{ScorerConfig, ScorerConfigError};
pub use exec::ExecScorer;

/// Build the OSS scorer registry, registering every built-in OSS scorer.
///
/// The OSS build registers only `exec` today (a future `http` scorer joins
/// here). The enterprise binary calls the same registry shape and adds
/// vendor adapters at its own init, so an `evals.scorers[].type` that names
/// a vendor in an OSS build resolves to the "not available in this build"
/// diagnostic with no runtime license check.
pub fn build_registry(
    scorers: &[ScorerConfig],
    telemetry: Arc<dyn TelemetrySink>,
) -> ScorerRegistry {
    let mut registry = ScorerRegistry::new().with_telemetry(telemetry);
    for cfg in scorers {
        if let ScorerConfig::Exec(exec_cfg) = cfg {
            registry.register(Arc::new(ExecScorer::new(exec_cfg.clone())));
        }
    }
    registry
}

#[cfg(test)]
mod tests {
    use super::*;
    use config::ExecScorerConfig;
    use mcptest_scorer_core::NullSink;

    #[test]
    fn registry_registers_configured_exec_scorer() {
        let cfg = ScorerConfig::Exec(ExecScorerConfig {
            name: "my-judge".into(),
            command: vec!["cat".into()],
            env: Default::default(),
            cwd: None,
            timeout_ms: 30_000,
        });
        let registry = build_registry(&[cfg], Arc::new(NullSink));
        assert!(registry.is_registered("exec"));
    }

    #[test]
    fn empty_config_registers_no_scorers() {
        let registry = build_registry(&[], Arc::new(NullSink));
        assert!(registry.registered_types().is_empty());
    }
}
