//! Shared reporter construction for the `run` and `report` surfaces.
//!
//! Both `mcptest run --reporter` and `mcptest report --format` turn a format
//! name into a `Box<dyn Reporter>`. Keeping that mapping in one place means a
//! new format (or a builder tweak like pretty's `--verbose`) lands in both
//! surfaces at once instead of drifting between two `match` arms.
//!
//! `upload` (report-only, a network push) and `quiet` (run-only, no output)
//! are not renderable formats, so they live on their own enums and are
//! handled by the callers before they reach [`build_reporter`].

use mcptest_core::report::reporters::{
    AgentReporter, GitlabReporter, HtmlReporter, JsonReporter, JunitReporter, MarkdownReporter,
    MatrixMarkdownReporter, MatrixReporter, NdjsonReporter, OpeninferenceReporter, PrettyReporter,
    SarifReporter, TapReporter, DEFAULT_TOKEN_BUDGET,
};
use mcptest_core::report::Reporter;

use crate::cli::global::AnnotationsMode;

/// Every format that renders a report to a writer. The shared subset of
/// `--reporter` (run) and `--format` (report), excluding the non-rendering
/// `quiet` and `upload` values.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum RenderFormat {
    /// Human-friendly text.
    Pretty,
    /// Single JSON document, round-trippable through `mcptest report`.
    Json,
    /// JUnit XML.
    Junit,
    /// GitHub-flavored Markdown.
    Md,
    /// Single-file HTML.
    Html,
    /// SARIF 2.1.0.
    Sarif,
    /// GitLab Code Quality JSON.
    Gitlab,
    /// Newline-delimited JSON (one record per line).
    Ndjson,
    /// Test Anything Protocol v14.
    Tap,
    /// Comparison-matrix grid (test x model) as a self-contained HTML file.
    Matrix,
    /// Comparison-matrix grid as GitHub-flavored Markdown.
    MatrixMd,
    /// Compact, model-facing output for an agent loop (see [`AgentReporter`]).
    Agent,
    /// OpenInference / OTLP-compatible trace spans as JSONL, for eval and
    /// observability platforms.
    Openinference,
}

/// Build the reporter for `format`. `verbose`, `juror_details`, and `color`
/// only affect the pretty reporter; `agent_budget` only affects the agent
/// reporter (its approximate token ceiling, defaulting to
/// [`DEFAULT_TOKEN_BUDGET`] when `None`); the others ignore them. `color` is
/// the already-resolved on/off (the caller decides via `--color` + the sink),
/// so a file sink or machine format passes `false`.
pub(crate) fn build_reporter(
    format: RenderFormat,
    verbose: bool,
    juror_details: bool,
    color: bool,
    agent_budget: Option<usize>,
) -> Box<dyn Reporter> {
    match format {
        RenderFormat::Pretty => Box::new(
            PrettyReporter::default()
                .with_verbose(verbose)
                .with_juror_details(juror_details)
                .with_color(color),
        ),
        RenderFormat::Json => Box::new(JsonReporter::default()),
        RenderFormat::Junit => Box::new(JunitReporter::default()),
        RenderFormat::Md => Box::new(MarkdownReporter::default()),
        RenderFormat::Html => Box::new(HtmlReporter::default()),
        RenderFormat::Sarif => Box::new(SarifReporter::default()),
        RenderFormat::Gitlab => Box::new(GitlabReporter::default()),
        RenderFormat::Ndjson => Box::new(NdjsonReporter::default()),
        RenderFormat::Tap => Box::new(TapReporter::default()),
        RenderFormat::Matrix => Box::new(MatrixReporter),
        RenderFormat::MatrixMd => Box::new(MatrixMarkdownReporter),
        RenderFormat::Agent => Box::new(
            AgentReporter::default()
                .with_token_budget(agent_budget.unwrap_or(DEFAULT_TOKEN_BUDGET)),
        ),
        RenderFormat::Openinference => Box::new(OpeninferenceReporter),
    }
}

/// Whether GitHub Actions annotations should be emitted, given the
/// `--annotations` mode. `Auto` emits only inside Actions (`GITHUB_ACTIONS`
/// is `true`), matching how the wrapper auto-detects its environment.
pub(crate) fn annotations_enabled(mode: AnnotationsMode) -> bool {
    match mode {
        AnnotationsMode::Always => true,
        AnnotationsMode::Never => false,
        AnnotationsMode::Auto => std::env::var("GITHUB_ACTIONS")
            .map(|v| v == "true")
            .unwrap_or(false),
    }
}
