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

use anyhow::Result;

use crate::cli::args::{
    IntrospectCliArgs, IntrospectFormatCli, ToolsCallCliArgs, ToolsCliArgs, ToolsSubcommand,
};
use crate::commands;

/// Selector for the introspection subcommands. Internal to dispatch so the
/// single [`introspect_command`] match arm can route each variant to the
/// matching [`commands::introspect`] entry point. `tools` has its own handler
/// ([`tools_command`]) because  gave it a `call` subcommand.
#[derive(Copy, Clone, Debug)]
pub(crate) enum IntrospectKind {
    Resources,
    Prompts,
    Capabilities,
}

/// Shared dispatch for the four imperative introspection subcommands
///. Builds a [`commands::IntrospectArgs`] from the CLI struct and
/// routes to the matching entry point.
pub(crate) fn introspect_command(args: IntrospectCliArgs, kind: IntrospectKind) -> Result<i32> {
    let bearer_token = args
        .bearer_token_env
        .as_ref()
        .and_then(|name| std::env::var(name).ok());
    let format = match args.format {
        IntrospectFormatCli::Pretty => commands::IntrospectFormat::Pretty,
        IntrospectFormatCli::Json => commands::IntrospectFormat::Json,
    };
    let plain = commands::IntrospectArgs {
        url: args.url,
        bearer_token,
        format,
    };
    match kind {
        IntrospectKind::Resources => commands::run_introspect_resources(plain),
        IntrospectKind::Prompts => commands::run_introspect_prompts(plain),
        IntrospectKind::Capabilities => commands::run_introspect_capabilities(plain),
    }
}

/// Dispatch for `mcptest tools`: list the catalog (bare form) or run one tool
/// with the pipeline primitives (`tools call`). Modeled as one handler so the
/// backward-compatible list form and the new `call` form share the same flag
/// parsing entry point.
pub(crate) fn tools_command(args: ToolsCliArgs) -> Result<i32> {
    match args.command {
        Some(ToolsSubcommand::Call(call)) => tools_call_command(call),
        None => {
            let url = args
                .url
                .ok_or_else(|| anyhow::anyhow!("`tools` requires --url (or use `tools call`)"))?;
            let bearer_token = args
                .bearer_token_env
                .as_ref()
                .and_then(|name| std::env::var(name).ok());
            let format = match args.format {
                IntrospectFormatCli::Pretty => commands::IntrospectFormat::Pretty,
                IntrospectFormatCli::Json => commands::IntrospectFormat::Json,
            };
            commands::run_introspect_tools(commands::IntrospectArgs {
                url,
                bearer_token,
                format,
            })
        }
    }
}

fn tools_call_command(call: ToolsCallCliArgs) -> Result<i32> {
    let bearer_token = call
        .bearer_token_env
        .as_ref()
        .and_then(|name| std::env::var(name).ok());
    let then = call.then.map(|tool| commands::ThenStep {
        tool,
        args: call.then_arg,
    });
    commands::run_tools_call(commands::ToolsCallArgs {
        url: call.url,
        bearer_token,
        tool: call.tool,
        args_json: call.args,
        args_from_stdin: call.args_from_stdin,
        arg_paths: call.arg,
        binds: call.bind,
        select: call.select,
        json: call.json,
        then,
        max_cost: call.max_cost,
    })
}
