//! Arguments for `mcptest conformance` (WOR-945).
//!
//! Three subcommands:
//!
//! - `run` scores a running MCP server against the vendored SEP
//!   corpus.
//! - `refresh` pulls the latest SEPs from upstream into the user
//!   cache.
//! - `check-ids` lists every `check:` id present in the resolved
//!   corpus's `traceability.json`, with an implementation marker.

use std::path::PathBuf;

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

/// Arguments for `mcptest conformance`.
#[derive(Debug, Args)]
pub struct ConformanceArgs {
    /// Which conformance operation to run.
    #[command(subcommand)]
    pub command: ConformanceCommand,
}

/// Subcommands for `mcptest conformance`.
#[derive(Debug, Subcommand)]
pub enum ConformanceCommand {
    /// Score a server against the vendored SEP corpus.
    Run(ConformanceRunArgs),
    /// Pull the latest SEPs from upstream into the user cache.
    Refresh(ConformanceRefreshArgs),
    /// List every check id in the resolved corpus and whether
    /// mcptest implements it.
    #[command(name = "check-ids")]
    CheckIds(ConformanceCheckIdsArgs),
}

/// Output format for the `run` subcommand.
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, ValueEnum)]
#[value(rename_all = "kebab-case")]
pub enum ConformanceFormat {
    /// 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 conformance run`.
#[derive(Debug, Args, Default)]
pub struct ConformanceRunArgs {
    /// MCP server to probe: an http(s) URL, or a command line that launches a
    /// stdio server (e.g. `mcptest mock --tools-from server.yml`). Same shape
    /// as `mcptest run`'s `--server-url` / `--server-command`. Without it,
    /// `conformance run` only counts documented requirements (no live probe).
    #[arg(long)]
    pub server: Option<String>,

    /// Command that runs a client-under-test, scored by the client lane
    /// (WOR-1365). The client speaks MCP over its own stdin/stdout: mcptest
    /// stands up an adversarial server and observes the client's handshake.
    /// Mutually exclusive with `--server`.
    #[arg(long, value_name = "COMMAND", conflicts_with = "server")]
    pub client: Option<String>,

    /// Which spec revision to score against. Defaults to the latest
    /// version available in the resolved corpus.
    #[arg(long, value_name = "VERSION")]
    pub target_version: Option<String>,

    /// Override the corpus directory. When set, the cache + embedded
    /// fallback are skipped.
    #[arg(long, value_name = "PATH")]
    pub corpus_dir: Option<PathBuf>,

    /// Output format. Same shape as `mcptest compliance --format`.
    #[arg(
        long,
        value_enum,
        value_name = "FORMAT",
        default_value_t = ConformanceFormat::Pretty
    )]
    pub format: ConformanceFormat,

    /// Where to write the report. Defaults to stdout. `--out` is
    /// accepted as a hidden alias for the pre-1.1 spelling.
    #[arg(long, alias = "out", value_name = "PATH")]
    pub output: Option<PathBuf>,

    /// When the requested version is missing locally, run a refresh
    /// before scoring. Off by default so a `run` never silently
    /// makes a network call.
    #[arg(long)]
    pub auto_refresh: bool,
}

/// Arguments for `mcptest conformance refresh`.
#[derive(Debug, Args, Default)]
pub struct ConformanceRefreshArgs {
    /// Spec version to fetch. `latest` resolves to the newest entry
    /// in `KNOWN_RELEASES`.
    #[arg(long, value_name = "VERSION", default_value = "latest")]
    pub target_version: String,

    /// Destination directory. Defaults to the user cache.
    #[arg(long, value_name = "PATH")]
    pub corpus_dir: Option<PathBuf>,

    /// Upstream repository URL.
    #[arg(
        long,
        value_name = "URL",
        default_value = "https://github.com/modelcontextprotocol/conformance"
    )]
    pub url: String,

    /// Pin to a specific upstream ref (tag or SHA). When set, the
    /// version-selection logic is bypassed.
    #[arg(long, value_name = "REF")]
    pub r#ref: Option<String>,

    /// Subdirectory in the upstream tree to mirror.
    #[arg(long, value_name = "PATH", default_value = "src/seps")]
    pub source_path: String,

    /// Print what would be fetched and where, without writing.
    #[arg(long)]
    pub dry_run: bool,
}

/// Arguments for `mcptest conformance check-ids`.
#[derive(Debug, Args, Default)]
pub struct ConformanceCheckIdsArgs {
    /// Which spec revision to inspect. Defaults to the latest
    /// version available in the resolved corpus.
    #[arg(long, value_name = "VERSION")]
    pub target_version: Option<String>,

    /// Override the corpus directory.
    #[arg(long, value_name = "PATH")]
    pub corpus_dir: Option<PathBuf>,

    /// Print only the unimplemented check ids (the
    /// implementation-coverage worklist).
    #[arg(long)]
    pub missing_only: bool,

    /// Output format. `pretty` is human-readable; `json` is
    /// scriptable.
    #[arg(
        long,
        value_enum,
        value_name = "FORMAT",
        default_value_t = ConformanceCheckIdsFormat::Pretty
    )]
    pub format: ConformanceCheckIdsFormat,
}

/// Output format for `check-ids`.
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, ValueEnum)]
#[value(rename_all = "kebab-case")]
pub enum ConformanceCheckIdsFormat {
    /// Human-readable list (default).
    #[default]
    Pretty,
    /// Machine-readable JSON.
    Json,
}
