percli 0.1.0

Offline CLI simulator for the Percolator risk engine
use anyhow::{Context, Result};

use crate::format::{self, OutputFormat};
use crate::scenario::{runner, Scenario};

pub fn run(
    path: &str,
    fmt: OutputFormat,
    _step_by_step: bool,
    check_conservation: bool,
    _verbose: bool,
) -> Result<()> {
    let content = std::fs::read_to_string(path)
        .with_context(|| format!("failed to read scenario file: {path}"))?;

    let scenario: Scenario =
        toml::from_str(&content).with_context(|| format!("failed to parse scenario: {path}"))?;

    if !scenario.meta.name.is_empty() {
        eprintln!("Running: {}", scenario.meta.name);
        if !scenario.meta.description.is_empty() {
            eprintln!("  {}", scenario.meta.description);
        }
        eprintln!();
    }

    let opts = runner::RunOptions {
        check_conservation,
    };

    let result = runner::run_scenario(&scenario, &opts)?;

    format::print_run_result(&result, fmt);

    // Check for any assertion failures
    let failures: Vec<_> = result
        .step_results
        .iter()
        .filter(|sr| matches!(sr.outcome, runner::StepOutcome::AssertFailed(_)))
        .collect();

    if !failures.is_empty() {
        eprintln!();
        for f in &failures {
            if let runner::StepOutcome::AssertFailed(msg) = &f.outcome {
                eprintln!("ASSERTION FAILED at step {}: {msg}", f.step_num);
            }
        }
        std::process::exit(1);
    }

    Ok(())
}