//! Command-line interface definitions for `mcp-gateway`.
//!
//! Defines the top-level [`Cli`] struct parsed by `clap` and the [`Command`] /
//! [`CapCommand`] / [`ToolCommand`] / [`TlsCommand`] subcommand enums.
//!
//! # CLI Bridge
//!
//! The `tool` subcommand exposes every registered capability tool as a
//! composable shell command:
//!
//! ```bash
//! # Invoke any tool directly
//! mcp-gateway tool invoke weather_current location=London
//!
//! # Pipe JSON args from stdin
//! echo '{"location":"Helsinki"}' | mcp-gateway tool invoke weather_current
//!
//! # List available tools
//! mcp-gateway tool list --format table
//!
//! # Inspect a tool's schema
//! mcp-gateway tool inspect yahoo_stock_quote
//!
//! # Generate shell completions
//! mcp-gateway tool completions zsh > ~/.zsh/completions/_mcp-gateway
//! ```

pub mod completion;
pub mod identity;
pub mod invoke;
pub mod output;
pub mod skills;
pub mod subcommands;

use std::path::PathBuf;

use clap::{Parser, Subcommand, ValueEnum};
use clap_complete::Shell;

use crate::cli::output::OutputFormat;

pub use identity::{IdentityCommand, IdentityGrantScopeArg, IdentityGrantsCommand};
pub use skills::SkillsCommand;
pub use subcommands::{
    AuditCommand, CapCommand, KubernetesCommand, PluginCommand, ProtocolImportCommand,
    ProtocolImportKind, RankingCommand, RuntimeProviderArg, TlsCommand, TrustCommand,
    TrustLabCommand,
};

// ── Config-export CLI types ───────────────────────────────────────────────────
// Defined here (library crate) so both the CLI parser and the binary-only
// `commands/config_export.rs` can share the same type definitions.

/// Connection mode for the exported client config entry.
#[cfg(feature = "config-export")]
#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)]
pub enum ConnectionMode {
    /// HTTP proxy mode: client connects to the running gateway's HTTP endpoint.
    Proxy,
    /// Stdio mode: client spawns `mcp-gateway serve --stdio` as a subprocess.
    Stdio,
    /// Auto-detect: probe the health endpoint first; fall back to stdio, then proxy.
    Auto,
}

/// Target AI client for config export.
#[cfg(feature = "config-export")]
#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)]
pub enum ExportTarget {
    /// Claude Code (`~/.claude.json`)
    ClaudeCode,
    /// Claude Desktop (platform-specific path)
    ClaudeDesktop,
    /// Cursor (`.cursor/mcp.json`, workspace-relative)
    Cursor,
    /// VS Code Copilot (`.vscode/mcp.json`, workspace-relative)
    VsCodeCopilot,
    /// Windsurf (`~/.codeium/windsurf/mcp_config.json`)
    Windsurf,
    /// Cline (`.cline/mcp_servers.json`, workspace-relative)
    Cline,
    /// Zed (`~/.config/zed/settings.json`)
    Zed,
    /// Generic: write to stdout
    Generic,
    /// All supported clients
    All,
}

/// Starter configuration profile for `mcp-gateway init`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub enum InitProfile {
    /// Self-contained local developer setup with zero-key sample capabilities.
    Local,
    /// Minimal skeleton config for operators who want to add everything manually.
    Minimal,
}

impl std::fmt::Display for InitProfile {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(match self {
            Self::Local => "local",
            Self::Minimal => "minimal",
        })
    }
}

/// Universal MCP Gateway - single-port multiplexing for MCP servers and REST APIs
///
/// Aggregates multiple MCP backends and REST capability definitions behind one
/// endpoint. Meta-MCP mode (default) exposes a compact discovery + operations
/// surface so AI clients only load the tools they actually need instead of
/// preloading every backend schema into the prompt.
///
/// Run without a subcommand to start the gateway server.
#[derive(Parser, Debug)]
#[command(name = "mcp-gateway")]
#[command(version, about, long_about = None)]
pub struct Cli {
    /// Path to the gateway configuration file (YAML)
    #[arg(short, long, env = "MCP_GATEWAY_CONFIG", global = true)]
    pub config: Option<PathBuf>,

    /// Port the gateway listens on (overrides config file)
    #[arg(short, long, env = "MCP_GATEWAY_PORT")]
    pub port: Option<u16>,

    /// Host address to bind to (overrides config file)
    #[arg(long, env = "MCP_GATEWAY_HOST")]
    pub host: Option<String>,

    /// Minimum log level: trace, debug, info, warn, or error
    #[arg(
        long,
        default_value = "info",
        env = "MCP_GATEWAY_LOG_LEVEL",
        global = true
    )]
    pub log_level: String,

    /// Log output format: "text" for human-readable, "json" for structured
    #[arg(long, env = "MCP_GATEWAY_LOG_FORMAT", global = true)]
    pub log_format: Option<String>,

    /// Disable Meta-MCP mode and expose all tools directly
    #[arg(long)]
    pub no_meta_mcp: bool,

    /// Subcommand to run (defaults to server mode when omitted)
    #[command(subcommand)]
    pub command: Option<Command>,
}

/// Top-level subcommands
#[derive(Subcommand, Debug)]
pub enum Command {
    /// Start the gateway server (default when no subcommand is given)
    #[command(about = "Start the gateway server")]
    Serve {
        /// Run in stdio mode: read JSON-RPC from stdin, write responses to stdout.
        ///
        /// Skips the HTTP listener and speaks MCP over newline-delimited JSON-RPC,
        /// making `mcp-gateway` directly usable as a Claude Code / MCP stdio server:
        ///
        ///   `mcp-gateway serve --stdio`
        ///
        /// or simply:
        ///
        ///   `echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{...}}' | mcp-gateway serve --stdio`
        #[arg(long, default_value_t = false)]
        stdio: bool,
    },

    /// Manage capability definitions (validate, test, import, install)
    #[command(subcommand, about = "Capability management commands")]
    Cap(CapCommand),

    /// Preview safe protocol imports before writing or enabling generated tools
    #[command(
        subcommand,
        about = "Preview safe imports from API and MCP package sources"
    )]
    Import(ProtocolImportCommand),

    /// Plan enterprise Kubernetes reconciliation and validation.
    #[command(subcommand, about = "Kubernetes enterprise deployment commands")]
    Kubernetes(KubernetesCommand),

    /// Evaluate deterministic adaptive ranking fixtures.
    #[command(subcommand, about = "Adaptive ranking evaluation commands")]
    Ranking(RankingCommand),

    /// Manage TLS certificates for mTLS authenticated tool access (RFC-0051)
    #[command(
        subcommand,
        about = "Certificate lifecycle management (init-ca, issue-server, issue-client)"
    )]
    Tls(TlsCommand),

    /// Generate, inspect, and validate `TrustCard` and CBOM metadata.
    #[command(subcommand, about = "TrustCard and CBOM metadata commands")]
    Trust(TrustCommand),

    /// Manage caller identity and local personal-capability grants.
    #[command(subcommand, about = "Identity and local grant administration")]
    Identity(IdentityCommand),

    /// Generate a starter gateway.yaml with sensible defaults
    #[command(about = "Create a new gateway configuration file")]
    Init {
        /// File path to write the generated configuration to
        #[arg(short, long, default_value = "gateway.yaml")]
        output: PathBuf,

        /// Starter profile to generate
        #[arg(long, default_value = "local", value_enum)]
        profile: InitProfile,

        /// Include example capability definitions and backend stubs
        #[arg(long, default_value = "true")]
        with_examples: bool,
    },

    /// Fetch live statistics from a running gateway instance
    #[command(about = "Show invocation counts, cache hits, and token savings")]
    Stats {
        /// Base URL of the running gateway (without /mcp suffix).
        ///
        /// Defaults to the `server.host`/`server.port` of `--config` (the same
        /// file `serve` binds to), falling back to `http://127.0.0.1:39400`
        /// when no config is found. An explicit `--url` always overrides both.
        #[arg(short, long)]
        url: Option<String>,

        /// Token price per million (USD) for estimated cost savings
        #[arg(short, long, default_value_t = 15.0)]
        price: f64,
    },

    /// Lint capability YAMLs against agent-UX best practices
    ///
    /// Validates one or more capability files (or directories) against the
    /// full agent-UX rules engine (AX-001..AX-009) and reports issues with
    /// colored output. Supports JSON, SARIF, and auto-fix modes.
    #[command(about = "Validate capability definitions against agent-UX rules")]
    Validate {
        /// Files or directories to validate (YAML capabilities)
        #[arg(required = true)]
        paths: Vec<PathBuf>,

        /// Output format
        #[arg(short, long, default_value = "text", value_enum)]
        format: crate::validator::OutputFormat,

        /// Minimum severity to report
        #[arg(short, long, default_value = "info", value_enum)]
        severity: crate::validator::SeverityFilter,

        /// Auto-fix issues where possible (rewrites YAML in place)
        #[arg(long)]
        fix: bool,

        /// Disable colored output
        #[arg(long)]
        no_color: bool,
    },

    /// Invoke gateway tools directly from the shell without a running server
    ///
    /// Loads capabilities from the configured directory and exposes them as
    /// composable CLI commands.  Supports JSON args from stdin for piping:
    ///
    ///   `echo '{"location":"London"}' | mcp-gateway tool invoke weather_current`
    #[command(subcommand, about = "Invoke gateway tools directly from the CLI")]
    Tool(ToolCommand),

    /// Generate agent skill bundles from capability definitions
    ///
    /// Converts loaded capability YAML files into Markdown skill bundles
    /// that AI agents can discover and load via the `loadSkill` convention.
    #[command(subcommand, about = "Generate agent skill bundles")]
    Skills(SkillsCommand),

    /// Manage gateway plugins from the marketplace
    ///
    /// Search, install, uninstall, and list gateway plugins sourced from the
    /// remote plugin marketplace.
    #[command(subcommand, about = "Plugin marketplace management")]
    Plugin(PluginCommand),

    /// Setup wizard and config export — import MCP servers or export gateway config
    ///
    /// Two sub-modes:
    ///   `setup wizard`  — scan AI clients and import MCP servers into gateway.yaml
    ///   `setup export`  — write gateway config into AI client config files
    #[command(subcommand, about = "Setup wizard and config export")]
    Setup(SetupCommand),

    /// Add an MCP backend to the gateway configuration
    ///
    /// Compatible with `claude mcp add` and `codex mcp add` CLI conventions.
    /// If `name` matches a known server in the built-in registry (48 servers),
    /// the command and env-var template are filled automatically.
    ///
    /// # Examples
    ///
    /// ```bash
    /// # From built-in registry (knows the npx command + required env vars):
    /// mcp-gateway add tavily
    ///
    /// # Stdio server with trailing command (claude/codex style):
    /// mcp-gateway add my-server -- npx -y @some/mcp-server --flag
    ///
    /// # Stdio server with env vars:
    /// mcp-gateway add -e API_KEY=xxx my-server -- npx my-mcp-server
    ///
    /// # HTTP server:
    /// mcp-gateway add --url https://mcp.sentry.dev/mcp sentry
    ///
    /// # Both styles work:
    /// mcp-gateway add --command "npx -y @anthropic/mcp-server-tavily" tavily
    /// ```
    #[command(about = "Add an MCP backend to gateway.yaml")]
    Add {
        /// Name for the new backend (used as the config key and registry lookup)
        name: String,

        /// HTTP URL for the server (streamable HTTP / SSE transport)
        #[arg(long)]
        url: Option<String>,

        /// Shell command as a single string (alternative to trailing `-- cmd args...`)
        #[arg(long)]
        command: Option<String>,

        /// Human-readable description (defaults to registry description when available)
        #[arg(long)]
        description: Option<String>,

        /// Environment variables, may be repeated (-e KEY=VALUE or --env KEY=VALUE)
        #[arg(short = 'e', long = "env", value_name = "KEY=VALUE")]
        env_vars: Vec<String>,

        /// Gateway config file to modify
        #[arg(short, long, default_value = "gateway.yaml")]
        config: PathBuf,

        /// Stdio command and arguments (after `--` separator, claude/codex style)
        #[arg(last = true)]
        trailing_command: Vec<String>,
    },

    /// Remove an MCP backend from the gateway configuration
    #[command(about = "Remove an MCP backend from gateway.yaml")]
    Remove {
        /// Name of the backend to remove
        name: String,

        /// Gateway config file to modify
        #[arg(short, long, default_value = "gateway.yaml")]
        config: PathBuf,
    },

    /// List configured MCP backends
    #[command(about = "List all configured backends")]
    List {
        /// Output as JSON (codex-compatible)
        #[arg(long)]
        json: bool,

        /// Gateway config file to read
        #[arg(short, long, default_value = "gateway.yaml")]
        config: PathBuf,
    },

    /// Get details about a specific MCP backend
    #[command(about = "Show details of a configured backend")]
    Get {
        /// Backend name to inspect
        name: String,

        /// Gateway config file to read
        #[arg(short, long, default_value = "gateway.yaml")]
        config: PathBuf,
    },

    /// Diagnose gateway and backend health
    ///
    /// Checks configuration, port availability, required env vars, HTTP
    /// reachability for HTTP backends, and whether any AI client is already
    /// pointed at the gateway.
    ///
    /// With `--shadow`, skips the health checks and instead emits DLP/firewall
    /// regex rules for operator-side network detection of MCP traffic.  These
    /// are **heuristic guidance** for external tools (firewalls, SIEMs, proxies)
    /// — the gateway does not intercept arbitrary outbound traffic itself.
    ///
    /// # Examples
    ///
    /// ```bash
    /// # Emit shell-grep patterns (default)
    /// mcp-gateway doctor --shadow
    ///
    /// # Emit nginx log_format filter snippet
    /// mcp-gateway doctor --shadow --shadow-format nginx
    ///
    /// # Emit YAML rule set for SIEM import
    /// mcp-gateway doctor --shadow --shadow-format yaml
    /// ```
    #[command(about = "Check gateway configuration and backend health")]
    Doctor {
        /// Attempt to auto-fix issues where possible (e.g. create missing dirs)
        #[arg(long)]
        fix: bool,

        /// Gateway config file to inspect (auto-detected when omitted)
        #[arg(short, long)]
        config: Option<PathBuf>,

        /// Output format for health checks
        #[arg(short, long, default_value = "table", value_enum)]
        format: OutputFormat,

        /// Emit operator-facing DLP/firewall regex rules for network-layer MCP
        /// detection instead of running the normal health checks.
        ///
        /// Rules are heuristic only — the gateway cannot intercept arbitrary
        /// outbound traffic.  Deploy the exported rules in your firewall, SIEM,
        /// or reverse proxy to detect unauthorised MCP sessions.
        #[arg(long)]
        shadow: bool,

        /// Output format for `--shadow` rule export: "grep", "nginx", or "yaml"
        #[arg(long, default_value = "grep", value_name = "FORMAT")]
        shadow_format: String,
    },

    /// Apply pending post-upgrade migrations and update the version stamp
    ///
    /// Reads `~/.mcp-gateway/version.stamp`, compares it to the current binary
    /// version, backs up `gateway.yaml`, and runs any registered migrations.
    ///
    /// This is called automatically at `serve` startup; run it manually after
    /// a Homebrew `brew upgrade` or other out-of-band binary swap.
    ///
    /// # Examples
    ///
    /// ```bash
    /// # Run interactively after upgrading
    /// mcp-gateway upgrade
    ///
    /// # Preview changes without writing anything
    /// mcp-gateway upgrade --dry-run
    ///
    /// # Silent mode for post_install hooks (errors only)
    /// mcp-gateway upgrade --quiet
    /// ```
    #[command(about = "Apply post-upgrade migrations and update version stamp")]
    Upgrade {
        /// Show what would change without writing any files
        #[arg(long)]
        dry_run: bool,

        /// Suppress all output except errors (useful for Homebrew `post_install`)
        #[arg(long, short)]
        quiet: bool,

        /// Override the data directory (default: ~/.mcp-gateway)
        #[arg(long, env = "MCP_GATEWAY_CONFIG_DIR")]
        data_dir: Option<PathBuf>,
    },

    /// Transparency log audit — verify chain integrity and query by session
    ///
    /// # Examples
    ///
    /// ```bash
    /// # Verify the full hash chain
    /// mcp-gateway audit verify
    ///
    /// # Show entries for a specific session
    /// mcp-gateway audit show --session sess-abc123
    /// ```
    #[command(subcommand, about = "Transparency log audit commands")]
    Audit(AuditCommand),

    /// Dual-substrate OCI runtime abstraction (MIK-5226, B4-PLATFORM).
    #[cfg(feature = "runtime-substrate")]
    #[command(subcommand, about = "Sandbox runtime substrate commands (opt-in)")]
    Runtime(RuntimeCommand),
}

/// Runtime-substrate subcommands (feature `runtime-substrate`).
#[cfg(feature = "runtime-substrate")]
#[derive(Subcommand, Debug)]
pub enum RuntimeCommand {
    /// Compile a sandbox descriptor to its substrate bundle (gVisor OCI or
    /// Apple VM-spec), running schema + security preflight first.
    #[command(about = "Compile a sandbox descriptor (YAML/JSON) to a substrate bundle")]
    Compile {
        /// Path to the descriptor file (YAML or JSON).
        #[arg(value_name = "DESCRIPTOR")]
        descriptor: std::path::PathBuf,

        /// Compile for BOTH substrates and report cross-substrate divergence.
        #[arg(long, default_value_t = false)]
        both: bool,
    },
}

/// Setup subcommands: interactive import wizard or config export.
#[derive(Subcommand, Debug)]
pub enum SetupCommand {
    /// Interactive setup wizard — scan AI clients and import MCP servers
    ///
    /// Scans Claude Desktop, Claude Code, Cursor, Zed, Continue.dev, Codex and
    /// running processes for existing MCP servers, lets you pick which ones to
    /// import into the gateway config, and optionally writes the gateway entry
    /// back into each AI client so they point at the gateway instead.
    #[command(about = "Interactive setup wizard — import existing MCP servers")]
    Wizard {
        /// Skip all interactive prompts and import every discovered server
        #[arg(long)]
        yes: bool,

        /// Path to write (or update) the gateway configuration file
        #[arg(short, long, default_value = "gateway.yaml")]
        output: PathBuf,

        /// Also write the gateway URL into each detected AI client config
        #[arg(long)]
        configure_client: bool,
    },

    /// Export gateway.yaml as client-native MCP config files
    ///
    /// Generates JSON config entries for AI clients (Claude Code, Cursor, VS Code
    /// Copilot, Windsurf, Cline, Zed, Claude Desktop) from the single gateway.yaml.
    /// Supports HTTP proxy and stdio subprocess modes with auto-detection.
    ///
    /// # Examples
    ///
    /// ```bash
    /// # Export to all detected clients (auto-detect mode)
    /// mcp-gateway setup export --target all
    ///
    /// # Export only for Claude Code in stdio mode
    /// mcp-gateway setup export --target claude-code --mode stdio
    ///
    /// # Export in proxy mode with custom entry name
    /// mcp-gateway setup export --target all --mode proxy --name my-gateway
    ///
    /// # Watch for config changes and auto-regenerate all client configs
    /// mcp-gateway setup export --target all --watch
    ///
    /// # Dry-run: show what would be written without writing
    /// mcp-gateway setup export --target all --dry-run
    /// ```
    #[cfg(feature = "config-export")]
    #[command(about = "Generate client-specific MCP config files from gateway.yaml")]
    Export {
        /// Target client(s) to export for
        #[arg(short, long, default_value = "all", value_enum)]
        target: ExportTarget,

        /// Connection mode: proxy (HTTP URL), stdio (subprocess), or auto-detect
        #[arg(short, long, default_value = "auto", value_enum)]
        mode: ConnectionMode,

        /// Name for the gateway entry in client configs
        #[arg(short, long, default_value = "gateway")]
        name: String,

        /// Watch gateway.yaml for changes and auto-regenerate all client configs
        #[arg(short, long)]
        watch: bool,

        /// Show what would be written without actually writing anything
        #[arg(long)]
        dry_run: bool,

        /// Restore a client config from a backup created by this command
        #[arg(long, value_name = "BACKUP")]
        rollback: Option<PathBuf>,

        /// Gateway config file to read
        #[arg(short, long, default_value = "gateway.yaml")]
        config: PathBuf,
    },
}

/// Tool CLI subcommands
///
/// All subcommands support `--format json|table|plain` for pipe-friendly output.
#[derive(Subcommand, Debug)]
pub enum ToolCommand {
    /// Call a registered tool with JSON arguments
    ///
    /// Arguments can be supplied as:
    /// - A JSON blob via `--args '{"key": "value"}'`
    /// - Individual `key=value` pairs: `invoke weather_current location=London`
    /// - JSON piped on stdin: `echo '{"location":"London"}' | mcp-gateway tool invoke weather_current`
    ///
    /// Multiple sources are merged; command-line keys override stdin.
    #[command(about = "Call a tool with JSON arguments")]
    Invoke {
        /// Tool name to invoke
        #[arg(required = true)]
        tool: String,

        /// Directory containing capability YAML definitions
        #[arg(
            short = 'C',
            long,
            default_value = "capabilities",
            env = "MCP_GATEWAY_CAPABILITIES"
        )]
        capabilities: PathBuf,

        /// JSON argument blob (merged with key=value pairs)
        #[arg(short, long)]
        args: Option<String>,

        /// Additional key=value argument pairs (may be repeated)
        ///
        /// Values that look like JSON scalars (numbers, booleans, null,
        /// arrays, objects) are parsed as JSON; everything else is a string.
        #[arg(value_name = "KEY=VALUE")]
        kv_args: Vec<String>,

        /// Output format
        #[arg(short, long, default_value = "json", value_enum)]
        format: OutputFormat,
    },

    /// List tools from a local capability catalogue
    ///
    /// Scans a local directory of capability YAML files (default
    /// `./capabilities`, or `MCP_GATEWAY_CAPABILITIES`) and prints each tool
    /// with its description and authentication requirement. This is a local
    /// catalogue scan and is independent of your server config: it does not
    /// reflect `-c gateway.yaml` or `capabilities.enabled`. A configured
    /// gateway exposes its tools over MCP at runtime, not via this command.
    #[command(about = "List tools from a local capability catalogue")]
    List {
        /// Directory containing capability YAML definitions
        #[arg(
            short = 'C',
            long,
            default_value = "capabilities",
            env = "MCP_GATEWAY_CAPABILITIES"
        )]
        capabilities: PathBuf,

        /// Output format
        #[arg(short, long, default_value = "table", value_enum)]
        format: OutputFormat,
    },

    /// Show the input schema for a specific tool
    ///
    /// Prints the tool's description and its JSON Schema input definition,
    /// useful for discovering required/optional parameters before invoking.
    #[command(about = "Show a tool's input schema")]
    Inspect {
        /// Tool name to inspect
        #[arg(required = true)]
        tool: String,

        /// Directory containing capability YAML definitions
        #[arg(
            short = 'C',
            long,
            default_value = "capabilities",
            env = "MCP_GATEWAY_CAPABILITIES"
        )]
        capabilities: PathBuf,

        /// Output format
        #[arg(short, long, default_value = "table", value_enum)]
        format: OutputFormat,
    },

    /// Generate shell tab-completion scripts
    ///
    /// Outputs a completion script for the requested shell.  Tool names from
    /// the local capabilities directory are injected as completions for the
    /// `invoke` and `inspect` subcommands.
    ///
    /// # Install
    ///
    ///   mcp-gateway tool completions zsh > ~/.zsh/completions/_mcp-gateway
    ///   mcp-gateway tool completions bash >> ~/.bashrc
    ///   mcp-gateway tool completions fish > ~/.config/fish/completions/mcp-gateway.fish
    #[command(about = "Generate shell completions")]
    Completions {
        /// Target shell
        #[arg(required = true, value_enum)]
        shell: Shell,

        /// Directory containing capability YAML definitions
        #[arg(
            short = 'C',
            long,
            default_value = "capabilities",
            env = "MCP_GATEWAY_CAPABILITIES"
        )]
        capabilities: PathBuf,
    },
}
