//! Compliance-flavored report fixture.
//!
//! Lives in a sibling module (like the matrix fixture in
//! [`super::matrix_section`]) so [`super`] stays under the
//! production-module-size guard while the fixture remains reachable via
//! [`Report::sample_full`](super::Report::sample_full).

use crate::compliance::RuleSeverity;

use super::{Report, RunSummary, TestFailure, TestResult, TestStatus};

/// Body of [`Report::sample_full`](super::Report::sample_full): every
/// test traces back to a registered compliance rule (`PROTO-001`,
/// `EDGE-005`, `RES-001`) so the SARIF and GitLab reporters can exercise
/// the per-rule `rule_id` and severity branches without reaching outside
/// this crate. Mix of MUST/SHOULD/MAY failures plus one pass keeps the
/// fixture honest against the severity matrix.
pub(super) fn sample_full_report() -> Report {
    let tests = vec![
        compliance_case(
            "PROTO-001: initialize handshake required",
            Some("server replied before completing initialize"),
            "compliance/v2024-11-05/proto-001.yml",
            12,
            "PROTO-001",
            RuleSeverity::Must,
            120,
        ),
        compliance_case(
            "EDGE-005: server tolerates whitespace-only id",
            Some("server returned -32603 instead of accepting the id"),
            "compliance/v2024-11-05/edge-005.yml",
            7,
            "EDGE-005",
            RuleSeverity::Should,
            90,
        ),
        compliance_case(
            "RES-001: resources/list returns an array",
            Some("resources field was missing on the response"),
            "compliance/v2024-11-05/res-001.yml",
            4,
            "RES-001",
            RuleSeverity::May,
            150,
        ),
        compliance_case(
            "TOOL-001: tools/list returns a non-empty array",
            None,
            "compliance/v2024-11-05/tool-001.yml",
            3,
            "TOOL-001",
            RuleSeverity::Must,
            52,
        ),
    ];
    Report {
        schema_version: "0.1".into(),
        mcptest_version: crate::version::full().into(),
        generated_at: "2026-05-15T22:14:03Z".into(),
        run_id: "01JCQQYV4S3H6KX7M8RN2T5XZF".into(),
        summary: RunSummary {
            duration_ms: 412,
            started_at: Some("2026-05-15T22:14:03Z".into()),
            ended_at: Some("2026-05-15T22:14:03.412Z".into()),
            ..RunSummary::from_tests(&tests)
        },
        tests,
        cost: None,
        metadata: None,
        matrix: None,
        protocol_violations: Vec::new(),
    }
}

/// Build one compliance-flavored [`TestResult`] for [`sample_full_report`].
///
/// Extracted so the fixture builder stays under the function-length lint
/// as the result model grows. A `Some(message)` marks a failed rule; a
/// `None` marks a passing one.
fn compliance_case(
    name: &str,
    failure_message: Option<&str>,
    file: &str,
    line: u32,
    rule_id: &str,
    severity: RuleSeverity,
    duration_ms: u64,
) -> TestResult {
    let (status, failure) = match failure_message {
        Some(message) => (
            TestStatus::Fail,
            Some(TestFailure {
                message: message.into(),
                diff: None,
                network_diagnostic: None,
            }),
        ),
        None => (TestStatus::Pass, None),
    };
    TestResult {
        name: name.into(),
        status,
        duration_ms,
        cache_hit: false,
        started_at: None,
        ended_at: None,
        failure,
        file: Some(file.into()),
        line: Some(line),
        steps: Vec::new(),
        consensus: None,
        rule_id: Some(rule_id.into()),
        severity: Some(severity),
        score: None,
        derived_metrics: Vec::new(),
        natural_language: false,
    }
}
