//! Integration tests for the jury confidence band and escalation flag.
//!
//! These ride on the public engine entry point
//! [`mcptest_core::eval::jury::engine::evaluate_with_jury`] and assert the
//! verdict the reporters and scorecard consume carries the right
//! [`mcptest_core::eval::jury::agreement::ConfidenceBand`] and escalation
//! flag. The band is a relabel of the existing inter-juror agreement
//! interpretation (ADR 0030); no new statistic is introduced. We also pin
//! backward compatibility: a report serialized before this ticket still
//! deserializes with the new fields defaulted.

use mcptest_core::eval::jury::agreement::ConfidenceBand;
use mcptest_core::eval::jury::engine::{evaluate_with_jury, ConsensusMethod, JurorVote, Vote};
use mcptest_core::eval::provider::ProviderId;
use mcptest_core::report::jury::{JuryConsensus, Verdict};

/// Build a passing juror vote at a given score so a test can shape the
/// score spread that drives the agreement metric.
fn vote(model: &str, score: f64) -> JurorVote {
    JurorVote {
        provider: ProviderId::Anthropic,
        model: model.into(),
        latency_ms: 100,
        cost_usd: Some(0.0001),
        tokens: None,
        weight: 1.0,
        result: Ok(Vote {
            verdict: Verdict::Pass,
            score: Some(score),
            reasoning: Some("ok".into()),
        }),
    }
}

#[test]
fn high_agreement_jury_reports_high_confidence_and_no_escalation() {
    let votes = vec![vote("a", 0.90), vote("b", 0.88), vote("c", 0.92)];
    let consensus = evaluate_with_jury(&votes, ConsensusMethod::Unanimous);
    assert_eq!(consensus.verdict, Verdict::Pass);
    assert_eq!(consensus.confidence, Some(ConfidenceBand::High));
    assert!(!consensus.escalate_for_review);
}

#[test]
fn split_jury_reports_low_confidence_and_sets_escalation_flag() {
    // A polarized score spread is below the 0.667 agreement threshold, so
    // the verdict keeps the majority pass but flags itself for review
    // rather than reporting a settled pass on a coin flip.
    let votes = vec![vote("a", 0.95), vote("b", 0.05), vote("c", 0.90)];
    let consensus = evaluate_with_jury(&votes, ConsensusMethod::Majority);
    assert_eq!(consensus.verdict, Verdict::Pass);
    assert_eq!(consensus.confidence, Some(ConfidenceBand::Low));
    assert!(consensus.escalate_for_review);
}

#[test]
fn confidence_and_escalation_round_trip_through_json() {
    let votes = vec![vote("a", 0.95), vote("b", 0.05), vote("c", 0.90)];
    let consensus = evaluate_with_jury(&votes, ConsensusMethod::Majority);
    let json = serde_json::to_string(&consensus).expect("serialize");
    let back: JuryConsensus = serde_json::from_str(&json).expect("deserialize");
    assert_eq!(back.confidence, Some(ConfidenceBand::Low));
    assert!(back.escalate_for_review);
}

#[test]
fn legacy_consensus_without_band_or_flag_still_deserializes() {
    // A report written before  has neither the confidence band nor
    // the escalation flag. The serde defaults fill them in so old
    // cassettes and uploaded reports keep parsing.
    let legacy = r#"{
        "verdict": "pass",
        "method": "majority",
        "score": 0.8,
        "total_cost_usd": 0.00021,
        "jurors": []
    }"#;
    let consensus: JuryConsensus = serde_json::from_str(legacy).expect("legacy shape parses");
    assert_eq!(consensus.verdict, Verdict::Pass);
    assert_eq!(consensus.confidence, None);
    assert!(!consensus.escalate_for_review);
}
