//! Arguments for the introspection subcommands and the imperative
//! `tools call` with pipeline primitives.

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

use crate::cli::parsers::{parse_arg_path, parse_dollar_amount, parse_then_arg};

/// Arguments for the four introspection subcommands.
///
/// Shared across `tools`, `resources`, `prompts`, and `capabilities` so a
/// future addition (for example `notifications`) inherits the same flag
/// surface without duplicating fields.
#[derive(Debug, Args)]
pub struct IntrospectCliArgs {
    /// MCP server endpoint to introspect.
    #[arg(long, value_name = "URL")]
    pub url: String,

    /// Env var that holds a bearer token to attach to every request.
    #[arg(long = "bearer-token-env", value_name = "NAME")]
    pub bearer_token_env: Option<String>,

    /// Output format. Default `pretty`; pass `json` to pipe wire-format
    /// payloads into `jq`.
    #[arg(
        long,
        value_enum,
        value_name = "FORMAT",
        default_value_t = IntrospectFormatCli::Pretty
    )]
    pub format: IntrospectFormatCli,
}

/// Output formats accepted by the introspection subcommands.
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, ValueEnum)]
#[value(rename_all = "kebab-case")]
pub enum IntrospectFormatCli {
    /// Human-friendly tabular output (default).
    #[default]
    Pretty,
    /// Pretty-printed JSON of the on-wire response.
    Json,
}

/// Arguments for `mcptest tools`.
///
/// Bare `mcptest tools --url ...` lists the catalog (the  behavior).
/// `mcptest tools call <tool> ...` runs one tool with the pipeline primitives.
/// Modeled as an optional subcommand so the bare form stays backward
/// compatible while `call` gains its own flag surface.
#[derive(Debug, Args)]
pub struct ToolsCliArgs {
    /// MCP server endpoint. Required for the list form; the `call`
    /// subcommand carries its own `--url` so it reads naturally.
    #[arg(long, value_name = "URL", required = false)]
    pub url: Option<String>,

    /// Env var that holds a bearer token to attach to every request.
    #[arg(long = "bearer-token-env", value_name = "NAME")]
    pub bearer_token_env: Option<String>,

    /// Output format for the list form.
    #[arg(
        long,
        value_enum,
        value_name = "FORMAT",
        default_value_t = IntrospectFormatCli::Pretty
    )]
    pub format: IntrospectFormatCli,

    /// Optional `call` subcommand.
    #[command(subcommand)]
    pub command: Option<ToolsSubcommand>,
}

/// Subcommands under `mcptest tools`.
#[derive(Debug, Subcommand)]
pub enum ToolsSubcommand {
    /// Call one tool, with JSONPath arg extraction, bind/then chaining, and
    /// output projection.
    Call(ToolsCallCliArgs),
}

/// Arguments for `mcptest tools call <tool>`.
///
/// The flag surface is the chaining contract from the ticket: extract args
/// from stdin (`--arg`, `--args-from-stdin`), pass a literal args object
/// (`--args`), capture from output (`--bind`), chain one call (`--then`), and
/// project the result (`--select`). The budget flags mirror `mcptest pipe`
/// for parity.
#[derive(Debug, Args)]
pub struct ToolsCallCliArgs {
    /// Tool to call.
    #[arg(value_name = "TOOL")]
    pub tool: String,

    /// MCP server endpoint.
    #[arg(long, value_name = "URL")]
    pub url: String,

    /// Env var that holds a bearer token to attach to every request.
    #[arg(long = "bearer-token-env", value_name = "NAME")]
    pub bearer_token_env: Option<String>,

    /// Literal args object as a JSON string.
    #[arg(long, value_name = "JSON")]
    pub args: Option<String>,

    /// Read the entire args object from stdin JSON.
    #[arg(long = "args-from-stdin", conflicts_with = "args")]
    pub args_from_stdin: bool,

    /// Extract a value from stdin JSON by JSONPath and use it as the named
    /// arg. Repeatable. Format `name=$.path`.
    #[arg(long = "arg", value_name = "NAME=PATH", value_parser = parse_arg_path)]
    pub arg: Vec<(String, String)>,

    /// Capture a value from this call's output by JSONPath, for a chained
    /// `--then` step. Repeatable. Format `name=$.path`.
    #[arg(long = "bind", value_name = "NAME=PATH", value_parser = parse_arg_path)]
    pub bind: Vec<(String, String)>,

    /// Chain a second tool call within this invocation.
    #[arg(long = "then", value_name = "TOOL")]
    pub then: Option<String>,

    /// Argument for the chained `--then` step. Repeatable. Format
    /// `name=value` or `name=:bound` to reference a `--bind` capture.
    #[arg(long = "then-arg", value_name = "NAME=VALUE", value_parser = parse_then_arg)]
    pub then_arg: Vec<(String, String)>,

    /// Project the output by JSONPath before printing.
    #[arg(long, value_name = "PATH")]
    pub select: Option<String>,

    /// Emit JSON instead of pretty output.
    #[arg(long)]
    pub json: bool,

    /// Aggregate USD ceiling across both calls in this invocation.
    #[arg(long = "max-cost", value_name = "USD", value_parser = parse_dollar_amount)]
    pub max_cost: Option<f64>,
}
