//! The comparison-matrix section carried on a [`crate::report::Report`].
//!
//! Split out of [`super`] so the report module stays under the size ceiling.
//! Both types are re-exported from [`crate::report`], so `report::MatrixReport`
//! and `report::MatrixCell` resolve unchanged.

use serde::{Deserialize, Serialize};

/// The comparison-matrix section of a [`crate::report::Report`].
///
/// One [`MatrixCell`] per (agent test, model/prompt) pair. A reporter pivots
/// these into a grid: rows are agent tests, columns are model labels, and each
/// cell joins back to the per-test rows in [`crate::report::Report::tests`] by
/// name for status and score.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct MatrixReport {
    /// Every cell dispatched in the run, in declaration order.
    pub cells: Vec<MatrixCell>,
}

/// One cell of a comparison matrix: an agent test evaluated under one
/// model/prompt, naming the [`crate::report::Report::tests`] rows it produced.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct MatrixCell {
    /// Agent test name. The grid groups rows by this.
    pub agent: String,
    /// Model or prompt display label. The grid groups columns by this.
    pub label: String,
    /// Names of the [`crate::report::Report::tests`] entries this cell produced
    /// (one per `runs:` iteration), used to join back to status and score.
    pub rows: Vec<String>,
}

/// Build the comparison-matrix fixture backing [`crate::report::Report::sample_matrix`].
///
/// Lives here (rather than inline in the `Report` impl) so the report module
/// stays under the size ceiling. Two agent tests across two models, one failing
/// cell, so reporters have a pass cell, a fail cell with a drill-down, and
/// non-trivial row/column pass rates.
pub(super) fn sample_matrix_report() -> super::Report {
    use super::{Report, RunSummary, TestFailure, TestResult, TestStatus};
    fn row(name: &str, pass: bool, score: f64) -> TestResult {
        let (status, failure) = if pass {
            (TestStatus::Pass, None)
        } else {
            (
                TestStatus::Fail,
                Some(TestFailure {
                    message: "judge score below threshold".into(),
                    diff: None,
                    network_diagnostic: None,
                }),
            )
        };
        TestResult {
            name: name.into(),
            status,
            duration_ms: 10,
            cache_hit: false,
            started_at: None,
            ended_at: None,
            failure,
            file: None,
            line: None,
            steps: Vec::new(),
            consensus: None,
            rule_id: None,
            severity: None,
            score: Some(score),
            derived_metrics: Vec::new(),
            natural_language: false,
        }
    }
    fn cell(agent: &str, label: &str) -> MatrixCell {
        MatrixCell {
            agent: agent.into(),
            label: label.into(),
            rows: vec![format!("{agent} [{label}]")],
        }
    }
    let tests = vec![
        row("summarize [gpt-4o]", true, 0.92),
        row("summarize [claude-3-5-sonnet]", false, 0.41),
        row("translate [gpt-4o]", true, 0.88),
        row("translate [claude-3-5-sonnet]", true, 0.79),
    ];
    Report {
        schema_version: "0.1".into(),
        mcptest_version: crate::version::full().into(),
        generated_at: "2026-06-05T00:00:00Z".into(),
        run_id: "matrix-sample".into(),
        summary: RunSummary {
            duration_ms: 40,
            ..RunSummary::from_tests(&tests)
        },
        tests,
        cost: None,
        metadata: None,
        matrix: Some(MatrixReport {
            cells: vec![
                cell("summarize", "gpt-4o"),
                cell("summarize", "claude-3-5-sonnet"),
                cell("translate", "gpt-4o"),
                cell("translate", "claude-3-5-sonnet"),
            ],
        }),
        protocol_violations: Vec::new(),
    }
}
