//! Integration tests for `mcptest policy simulate`.
//!
//! Drives the binary over a saved run report and a small policy, asserting the
//! verdict text and the exit code (the governance signal): a dry-run always
//! exits 0, `--gate` exits 1 on a failing verdict, an active waiver suppresses
//! a failure, and an expired waiver fails closed.

use assert_cmd::Command;
use predicates::prelude::*;
use tempfile::tempdir;

fn mcptest() -> Command {
    Command::cargo_bin("mcptest").expect("binary builds")
}

fn write(path: &std::path::Path, body: &str) {
    std::fs::write(path, body).unwrap();
}

/// A clean run report: three tests, none failed.
fn clean_run_report() -> &'static str {
    "{\"summary\":{\"total\":3,\"passed\":3,\"failed\":0,\"skipped\":0,\"duration_ms\":1}}"
}

/// A failing run report: one of three tests failed.
fn failing_run_report() -> &'static str {
    "{\"summary\":{\"total\":3,\"passed\":2,\"failed\":1,\"skipped\":0,\"duration_ms\":1}}"
}

/// A minimal policy that only forbids failed tests.
fn no_fail_policy() -> &'static str {
    "version: \"1.0\"\nrules:\n  - id: no-failed-tests\n    fact: run.failed\n    max: 0\n"
}

#[test]
fn a_passing_policy_over_a_run_report_succeeds() {
    let dir = tempdir().unwrap();
    let report = dir.path().join("run.json");
    let policy = dir.path().join("policy.yml");
    write(&report, clean_run_report());
    write(&policy, no_fail_policy());

    mcptest()
        .args([
            "policy",
            "simulate",
            "--policy",
            policy.to_str().unwrap(),
            "--run-report",
            report.to_str().unwrap(),
        ])
        .assert()
        .success()
        .stdout(predicate::str::contains("pass"));
}

#[test]
fn a_failing_policy_with_gate_exits_one() {
    let dir = tempdir().unwrap();
    let report = dir.path().join("run.json");
    let policy = dir.path().join("policy.yml");
    write(&report, failing_run_report());
    write(&policy, no_fail_policy());

    mcptest()
        .args([
            "policy",
            "simulate",
            "--policy",
            policy.to_str().unwrap(),
            "--run-report",
            report.to_str().unwrap(),
            "--gate",
        ])
        .assert()
        .code(1)
        .stdout(predicate::str::contains("no-failed-tests"))
        .stdout(predicate::str::contains("FAIL"));
}

#[test]
fn a_failing_policy_without_gate_still_exits_zero() {
    let dir = tempdir().unwrap();
    let report = dir.path().join("run.json");
    let policy = dir.path().join("policy.yml");
    write(&report, failing_run_report());
    write(&policy, no_fail_policy());

    mcptest()
        .args([
            "policy",
            "simulate",
            "--policy",
            policy.to_str().unwrap(),
            "--run-report",
            report.to_str().unwrap(),
        ])
        .assert()
        .success()
        .stdout(predicate::str::contains("fail"))
        .stdout(predicate::str::contains("FAIL"));
}

#[test]
fn an_active_waiver_keeps_the_gate_green() {
    let dir = tempdir().unwrap();
    let report = dir.path().join("run.json");
    let policy = dir.path().join("policy.yml");
    write(&report, failing_run_report());
    write(
        &policy,
        "version: \"1.0\"\nrules:\n  - id: no-failed-tests\n    fact: run.failed\n    max: 0\nwaivers:\n  - rule: no-failed-tests\n    owner: alice\n    reason: known flake\n    expiry: \"2099-01-01T00:00:00Z\"\n",
    );

    mcptest()
        .args([
            "policy",
            "simulate",
            "--policy",
            policy.to_str().unwrap(),
            "--run-report",
            report.to_str().unwrap(),
            "--gate",
        ])
        .assert()
        .success()
        .stdout(predicate::str::contains("WAIVED"));
}

#[test]
fn an_expired_waiver_fails_closed_under_gate() {
    let dir = tempdir().unwrap();
    let report = dir.path().join("run.json");
    let policy = dir.path().join("policy.yml");
    write(&report, failing_run_report());
    write(
        &policy,
        "version: \"1.0\"\nrules:\n  - id: no-failed-tests\n    fact: run.failed\n    max: 0\nwaivers:\n  - rule: no-failed-tests\n    owner: alice\n    reason: stale\n    expiry: \"2000-01-01T00:00:00Z\"\n",
    );

    mcptest()
        .args([
            "policy",
            "simulate",
            "--policy",
            policy.to_str().unwrap(),
            "--run-report",
            report.to_str().unwrap(),
            "--gate",
        ])
        .assert()
        .code(1)
        .stdout(predicate::str::contains("EXPIRED-WAIVER"))
        .stdout(predicate::str::contains("expired"));
}

#[test]
fn json_format_emits_a_verdict_field() {
    let dir = tempdir().unwrap();
    let report = dir.path().join("run.json");
    let policy = dir.path().join("policy.yml");
    write(&report, clean_run_report());
    write(&policy, no_fail_policy());

    mcptest()
        .args([
            "policy",
            "simulate",
            "--policy",
            policy.to_str().unwrap(),
            "--run-report",
            report.to_str().unwrap(),
            "--format",
            "json",
        ])
        .assert()
        .success()
        .stdout(predicate::str::contains("\"verdict\""));
}
