//! Integration tests for `mcptest judge certify`.
//!
//! Drives the binary over a labeled anchor set and a rubric, asserting the
//! exit code (the governance signal) and the JSON record, including the
//! corrected-rate path and the load-error path.

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();
}

/// Twenty rows, perfectly calibrated (confident-and-right, unconfident-and-wrong):
/// ECE and Brier are both 0 and the set clears the 10-sample floor.
fn calibrated_labels() -> String {
    let mut s = String::new();
    for _ in 0..10 {
        s.push_str("{\"confidence\": 1.0, \"correct\": true}\n");
        s.push_str("{\"confidence\": 0.0, \"correct\": false}\n");
    }
    s
}

#[test]
fn a_calibrated_judge_certifies_and_exits_zero() {
    let dir = tempdir().unwrap();
    let labels = dir.path().join("labels.jsonl");
    let rubric = dir.path().join("rubric.md");
    write(&labels, &calibrated_labels());
    write(&rubric, "Score the answer 0..1 on correctness.\n");

    mcptest()
        .args([
            "judge",
            "certify",
            "--labels",
            labels.to_str().unwrap(),
            "--rubric",
            rubric.to_str().unwrap(),
        ])
        .assert()
        .success()
        .stdout(predicate::str::contains("\"certified\": true"))
        .stdout(predicate::str::contains("rubric_hash"))
        .stdout(predicate::str::contains("anchor_set_hash"))
        .stdout(predicate::str::contains("valid_until"));
}

#[test]
fn an_overconfident_judge_is_not_certified_and_exits_one() {
    let dir = tempdir().unwrap();
    let labels = dir.path().join("labels.jsonl");
    let rubric = dir.path().join("rubric.md");
    // Always full confidence, right half the time: ECE 0.5.
    let mut body = String::new();
    for i in 0..20 {
        body.push_str(&format!(
            "{{\"confidence\": 1.0, \"correct\": {}}}\n",
            i % 2 == 0
        ));
    }
    write(&labels, &body);
    write(&rubric, "rubric\n");

    mcptest()
        .args([
            "judge",
            "certify",
            "--labels",
            labels.to_str().unwrap(),
            "--rubric",
            rubric.to_str().unwrap(),
        ])
        .assert()
        .code(1)
        .stdout(predicate::str::contains("\"certified\": false"))
        .stderr(predicate::str::contains("not certified"));
}

#[test]
fn an_anchor_set_below_the_floor_is_not_certified() {
    let dir = tempdir().unwrap();
    let labels = dir.path().join("labels.jsonl");
    let rubric = dir.path().join("rubric.md");
    write(
        &labels,
        "{\"confidence\": 1.0, \"correct\": true}\n{\"confidence\": 0.0, \"correct\": false}\n",
    );
    write(&rubric, "rubric\n");

    mcptest()
        .args([
            "judge",
            "certify",
            "--labels",
            labels.to_str().unwrap(),
            "--rubric",
            rubric.to_str().unwrap(),
        ])
        .assert()
        .code(1)
        .stderr(predicate::str::contains("below the required minimum"));
}

#[test]
fn reliability_inputs_add_a_corrected_rate() {
    let dir = tempdir().unwrap();
    let labels = dir.path().join("labels.jsonl");
    let rubric = dir.path().join("rubric.md");
    write(&labels, &calibrated_labels());
    write(&rubric, "rubric\n");

    mcptest()
        .args([
            "judge",
            "certify",
            "--labels",
            labels.to_str().unwrap(),
            "--rubric",
            rubric.to_str().unwrap(),
            "--observed-positive-rate",
            "0.5",
            "--reliability",
            "tp:90,fn:10,tn:80,fp:20",
        ])
        .assert()
        .success()
        .stdout(predicate::str::contains("corrected_rate"));
}

#[test]
fn output_flag_writes_the_record_to_a_file() {
    let dir = tempdir().unwrap();
    let labels = dir.path().join("labels.jsonl");
    let rubric = dir.path().join("rubric.md");
    let out = dir.path().join("cert.json");
    write(&labels, &calibrated_labels());
    write(&rubric, "rubric\n");

    mcptest()
        .args([
            "judge",
            "certify",
            "--labels",
            labels.to_str().unwrap(),
            "--rubric",
            rubric.to_str().unwrap(),
            "--output",
            out.to_str().unwrap(),
        ])
        .assert()
        .success()
        .stdout(predicate::str::contains("certified:"));
    let body = std::fs::read_to_string(&out).unwrap();
    assert!(body.contains("\"certified\": true"));
    assert!(body.contains("mcptest.dev/judge-certification/v1"));
}

#[test]
fn a_missing_labels_file_is_an_error() {
    let dir = tempdir().unwrap();
    let rubric = dir.path().join("rubric.md");
    write(&rubric, "rubric\n");

    mcptest()
        .args([
            "judge",
            "certify",
            "--labels",
            dir.path().join("nope.jsonl").to_str().unwrap(),
            "--rubric",
            rubric.to_str().unwrap(),
        ])
        .assert()
        .failure();
}
