//! Arguments for `mcptest compliance`.

use std::path::PathBuf;

use clap::{Args, Subcommand, ValueEnum};

/// Output format for `mcptest compliance`.
///
/// Mirrors the four renderers in [`mcptest_core::compliance::renderers`].
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, ValueEnum)]
#[value(rename_all = "kebab-case")]
pub enum ComplianceFormat {
    /// Color-tinted plain text (default).
    #[default]
    Pretty,
    /// Pretty-printed JSON of the score envelope.
    Json,
    /// GitHub-flavored Markdown.
    Markdown,
    /// Self-contained HTML document.
    Html,
}

/// Arguments for `mcptest compliance`.
///
/// Wraps the `run` subcommand plus the baseline-aware flags. The
/// `run` subcommand executes the compliance corpus against the
/// configured server, scores the result via the rubric, and renders
/// the score in the chosen format.
#[derive(Debug, Args)]
pub struct ComplianceArgs {
    /// Which compliance operation to run.
    #[command(subcommand)]
    pub command: ComplianceCommand,
}

/// Subcommands for `mcptest compliance`.
// One variant's args struct is larger than the others (more so on Windows,
// where it trips `large_enum_variant`). This enum is parsed once at startup, so
// the size is immaterial; allow the lint rather than box a clap args type.
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Subcommand)]
pub enum ComplianceCommand {
    /// Run the compliance corpus and render the score.
    Run(ComplianceRunArgs),
    /// Evaluate spec-derived conformance invariants over a captured session,
    /// plus multi-server composition-safety checks.
    Invariants(ComplianceInvariantsArgs),
}

/// Output format for `mcptest compliance invariants`.
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, ValueEnum)]
#[value(rename_all = "kebab-case")]
pub enum InvariantsFormat {
    /// Plain text grouped by server (default).
    #[default]
    Pretty,
    /// JSON envelope of every invariant outcome and composition finding.
    Json,
}

/// Arguments for `mcptest compliance invariants`.
///
/// Reads a JSON capture file (one session object, or an array of sessions for
/// the composition mode) and scores it against the `INV-NNN` invariant family.
/// The capture is read from disk so the run is deterministic and offline,
/// suitable for a CI gate.
#[derive(Debug, Args)]
pub struct ComplianceInvariantsArgs {
    /// Path to the JSON capture file. A single session object runs the
    /// per-server invariants; an array of sessions also runs the multi-server
    /// composition-safety checks.
    #[arg(long = "capture", value_name = "PATH")]
    pub capture: PathBuf,

    /// Output format. Default `pretty`.
    #[arg(
        long,
        value_enum,
        value_name = "FORMAT",
        default_value_t = InvariantsFormat::Pretty
    )]
    pub format: InvariantsFormat,
}

/// Arguments for `mcptest compliance run`.
///
/// The runner integration is a follow-up ticket; for v1.0 this command
/// reads a pre-built `--results-from` JSON file containing
/// `CheckResult` records. The flag set is deliberately the same shape
/// the live runner will adopt so callers do not need to relearn the
/// interface when the live path lands.
#[derive(Debug, Args)]
pub struct ComplianceRunArgs {
    /// Output format. Default `pretty`.
    #[arg(
        long,
        value_enum,
        value_name = "FORMAT",
        default_value_t = ComplianceFormat::Pretty
    )]
    pub format: ComplianceFormat,

    /// Path to a JSON file holding the pre-computed `CheckResult`
    /// list. Mutually exclusive with [`Self::from_suite`].
    #[arg(
        long = "results-from",
        value_name = "PATH",
        conflicts_with = "from_suite"
    )]
    pub results_from: Option<PathBuf>,

    ///  live path: drive the MCP executor against this YAML
    /// suite and synthesize a `CheckResult` list from each test's
    /// outcome. Each YAML test's `name:` becomes the `rule_id`; the
    /// rubric scores them against the rule registry.
    #[arg(long = "from-suite", value_name = "PATH")]
    pub from_suite: Option<PathBuf>,

    /// Server label printed in the report header. Defaults to the
    /// global `--server-url` when omitted.
    #[arg(long = "server-label", value_name = "LABEL")]
    pub server_label: Option<String>,

    /// Path to the compliance rule registry YAML. Defaults to the
    /// in-tree `compliance/registry.yml` when omitted.
    #[arg(long = "registry", value_name = "PATH")]
    pub registry: Option<PathBuf>,

    /// Comma-separated capability list the server declared during
    /// `initialize` (for example `tools,resources`). The scorer uses
    /// this set to decide whether the tools, resources, and prompts
    /// sections are applicable.
    #[arg(long = "capabilities", value_name = "LIST")]
    pub capabilities: Option<String>,

    /// Path to a baseline file listing expected failures. Outcomes
    /// classify against the four `BaselineDecision` variants:
    /// `NormalPass` / `ExpectedFailure` exit 0, `NewRegression` /
    /// `StaleBaseline` exit 1.
    #[arg(long = "baseline", value_name = "PATH")]
    pub baseline: Option<PathBuf>,

    /// Alias for `--baseline`. Kept so docs and CI snippets that
    /// already say `--expected-failures` keep working.
    #[arg(long = "expected-failures", value_name = "PATH")]
    pub expected_failures: Option<PathBuf>,

    /// Regenerate the baseline file from the current run. Prompts for
    /// confirmation unless `--yes` is also set.
    #[arg(long = "update-baseline")]
    pub update_baseline: bool,

    /// Skip the confirmation prompt for `--update-baseline`. Used by
    /// CI scripts that have already gated the operation.
    #[arg(long = "yes")]
    pub yes: bool,

    /// Write the current run's scorecard (a serialized ComplianceScore) to
    /// this path. Commit the file and point a suite's
    /// `compliance.grade_delta.against:` at it to gate future runs against it.
    #[arg(long = "save-scorecard", value_name = "PATH")]
    pub save_scorecard: Option<PathBuf>,

    /// Also run the official `@modelcontextprotocol/conformance` suite
    /// (via `npx`) against the server named by the global `--server-url`
    /// and fold its results into the score alongside the native checks.
    /// Requires Node.js unless `--official-cmd` points elsewhere.
    #[arg(long = "official")]
    pub official: bool,

    /// Override the executable used for `--official`. Element of an
    /// argv, so a pinned local install (or a test stub) replaces the
    /// default `npx --yes @modelcontextprotocol/conformance@latest`.
    #[arg(long = "official-cmd", value_name = "BIN", requires = "official")]
    pub official_cmd: Option<String>,
}
