//! CLI argument definitions using Clap
//!
//! This module contains all CLI argument parsing definitions, including
//! the main CLI struct and all subcommands.

use clap::{Parser, Subcommand, ValueEnum};
use std::path::PathBuf;

/// Complexity threshold presets for different project types
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum ThresholdPreset {
    /// Strict thresholds for high code quality standards
    Strict,
    /// Balanced thresholds for typical projects (default)
    Balanced,
    /// Lenient thresholds for legacy or complex domains
    Lenient,
}

/// Debug output format options
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum DebugFormatArg {
    /// Human-readable text format
    Text,
    /// JSON format for programmatic analysis
    Json,
}

/// Functional analysis profile for purity checking
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum FunctionalAnalysisProfile {
    /// Strict profile for codebases emphasizing functional purity
    Strict,
    /// Balanced profile for typical Rust codebases (default)
    Balanced,
    /// Lenient profile for imperative-heavy codebases
    Lenient,
}

/// Debtmap - Code complexity sensor for AI-assisted development
#[derive(Parser, Debug)]
#[command(name = "debtmap")]
#[command(about = "Code complexity sensor for AI-assisted development", long_about = None)]
#[command(version)]
pub struct Cli {
    #[command(subcommand)]
    pub command: Commands,

    /// Show where each configuration value came from (spec 201)
    #[arg(long, global = true)]
    pub show_config_sources: bool,

    /// Custom config file path (overrides default locations)
    #[arg(long, global = true, env = "DEBTMAP_CONFIG")]
    pub config: Option<PathBuf>,
}

/// Available CLI subcommands
#[derive(Subcommand, Debug)]
#[allow(clippy::large_enum_variant)]
pub enum Commands {
    /// Analyze code for technical debt signals
    Analyze {
        /// Path to analyze
        path: PathBuf,

        /// Output format
        #[arg(
            short,
            long,
            value_enum,
            default_value = "terminal",
            help_heading = "Output Options"
        )]
        format: OutputFormat,

        /// Output file (defaults to stdout)
        #[arg(short, long, help_heading = "Output Options")]
        output: Option<PathBuf>,

        /// Complexity threshold
        #[arg(long, default_value = "10", help_heading = "Threshold Options")]
        threshold_complexity: u32,

        /// Duplication threshold (lines)
        #[arg(long, default_value = "50", help_heading = "Threshold Options")]
        threshold_duplication: usize,

        /// Complexity threshold preset (strict, balanced, lenient)
        #[arg(
            long = "threshold-preset",
            value_enum,
            help_heading = "Threshold Options"
        )]
        threshold_preset: Option<ThresholdPreset>,

        /// Languages to analyze
        #[arg(long, value_delimiter = ',')]
        languages: Option<Vec<String>>,

        /// LCOV coverage file for risk analysis and score dampening.
        /// Coverage data dampens debt scores for well-tested code (multiplier = 1.0 - coverage),
        /// surfacing untested complex functions. Total debt score with coverage ≤ score without.
        #[arg(
            long = "coverage-file",
            visible_alias = "lcov",
            help_heading = "Coverage and Risk Analysis"
        )]
        coverage_file: Option<PathBuf>,

        /// Enable context-aware risk analysis
        #[arg(
            long = "context",
            visible_alias = "enable-context",
            help_heading = "Coverage and Risk Analysis"
        )]
        enable_context: bool,

        /// Context providers to use (critical_path, dependency, git_history)
        #[arg(long = "context-providers", value_delimiter = ',')]
        context_providers: Option<Vec<String>>,

        /// Disable specific context providers
        #[arg(long = "disable-context", value_delimiter = ',')]
        disable_context: Option<Vec<String>>,

        /// Show only top N priority items
        #[arg(long = "top", visible_alias = "head")]
        top: Option<usize>,

        /// Show only bottom N priority items (lowest priority)
        #[arg(long = "tail")]
        tail: Option<usize>,

        /// Use summary format with tiered priority display (compact output)
        #[arg(long = "summary", short = 's')]
        summary: bool,

        /// Disable semantic analysis (fallback mode)
        #[arg(long = "semantic-off")]
        semantic_off: bool,

        /// Minimum priority to display (low, medium, high, critical)
        #[arg(long = "min-priority")]
        min_priority: Option<String>,

        /// Minimum score threshold for filtering T3/T4 recommendations (default: 3.0).
        /// T1 Critical Architecture and T2 Complex Untested items bypass this filter and are always shown.
        /// Overrides config file setting. Spec 193, 205.
        #[arg(long = "min-score")]
        min_score: Option<f64>,

        /// Filter by debt categories (comma-separated)
        #[arg(long = "filter", value_delimiter = ',')]
        filter_categories: Option<Vec<String>>,

        /// Group output by debt category
        #[arg(long = "group-by-category")]
        group_by_category: bool,

        /// Show filter statistics (how many items filtered and why)
        #[arg(long = "show-filter-stats")]
        show_filter_stats: bool,

        /// Increase verbosity level (can be repeated: -v, -vv, -vvv)
        /// -v: Show main score factors
        /// -vv: Show detailed calculations
        /// -vvv: Show all debug information
        #[arg(short = 'v', long = "verbose", action = clap::ArgAction::Count)]
        verbosity: u8,

        /// Use compact output format (minimal details, top metrics only)
        #[arg(short = 'c', long = "compact", conflicts_with = "verbosity")]
        compact: bool,

        /// Plain output mode: ASCII-only, no colors, no emoji, machine-parseable
        #[arg(long = "plain")]
        plain: bool,

        /// Detail level for diagnostic reports (summary, standard, comprehensive, debug)
        #[arg(long = "detail-level", default_value = "standard")]
        detail_level: Option<String>,

        /// Disable TUI progress visualization (use simple progress bars)
        #[arg(long = "no-tui")]
        no_tui: bool,

        /// Suppress progress output (quiet mode)
        #[arg(long = "quiet", short = 'q')]
        quiet: bool,

        /// Enable streaming output mode for large codebases (Spec 003).
        /// Streams results to output as they're generated with O(1) memory overhead.
        #[arg(long = "streaming")]
        streaming: bool,

        /// Output file for streaming mode (requires --streaming).
        /// Use "-" for stdout.
        #[arg(long = "stream-to", requires = "streaming")]
        stream_to: Option<PathBuf>,

        /// Disable context-aware false positive reduction (enabled by default)
        #[arg(long = "no-context-aware")]
        no_context_aware: bool,

        /// Show complexity attribution details
        #[arg(long = "attribution")]
        show_attribution: bool,

        /// Show only aggregated file-level scores
        #[arg(long = "aggregate-only")]
        aggregate_only: bool,

        /// Disable file-level aggregation
        #[arg(long = "no-aggregation")]
        no_aggregation: bool,

        /// File aggregation method (sum, weighted_sum, logarithmic_sum, max_plus_average)
        #[arg(long = "aggregation-method", default_value = "weighted_sum")]
        aggregation_method: Option<String>,

        /// Minimum number of problematic functions for file aggregation
        #[arg(long = "min-problematic")]
        min_problematic: Option<usize>,

        /// Disable parallel call graph construction (enabled by default)
        #[arg(long = "no-parallel")]
        no_parallel: bool,

        /// Number of threads for parallel processing (0 = use all cores)
        #[arg(long = "jobs", short = 'j', default_value = "0")]
        jobs: usize,

        /// Disable multi-pass analysis (use single-pass for performance)
        #[arg(long = "no-multi-pass")]
        no_multi_pass: bool,

        /// Maximum number of files to analyze (0 = no limit, default: no limit)
        #[arg(long = "max-files")]
        max_files: Option<usize>,

        /// Disable god object detection
        #[arg(long = "no-god-object")]
        no_god_object: bool,

        /// Minimum methods per god object split recommendation (Spec 190)
        #[arg(long = "min-split-methods", default_value = "10")]
        min_split_methods: usize,

        /// Minimum lines per god object split recommendation (Spec 190)
        #[arg(long = "min-split-lines", default_value = "150")]
        min_split_lines: usize,

        /// Show detailed module split recommendations for god objects and large files.
        /// This experimental feature suggests how to decompose large files into
        /// smaller, focused modules. Hidden by default.
        #[arg(long = "show-splits")]
        show_splits: bool,

        /// Disable public API detection heuristics for dead code analysis
        #[arg(long = "no-public-api-detection")]
        no_public_api_detection: bool,

        /// Public API confidence threshold (0.0-1.0) - functions above this are considered public APIs
        #[arg(long = "public-api-threshold", default_value = "0.7")]
        public_api_threshold: f32,

        /// Disable pattern recognition
        #[arg(long = "no-pattern-detection")]
        no_pattern_detection: bool,

        /// Enable specific patterns only (comma-separated: observer,singleton,factory,strategy,callback,template_method)
        #[arg(long = "patterns", value_delimiter = ',')]
        patterns: Option<Vec<String>>,

        /// Pattern confidence threshold (0.0 - 1.0)
        #[arg(long = "pattern-threshold", default_value = "0.7")]
        pattern_threshold: f32,

        /// Enable AST-based functional composition analysis (spec 111)
        #[arg(long = "ast-functional-analysis")]
        ast_functional_analysis: bool,

        /// Functional analysis profile (strict, balanced, lenient)
        #[arg(long = "functional-analysis-profile", value_enum)]
        functional_analysis_profile: Option<FunctionalAnalysisProfile>,

        /// Show dependency information (callers/callees) in output
        #[arg(long = "show-dependencies")]
        show_dependencies: bool,

        /// Hide dependency information (callers/callees) in output
        #[arg(long = "no-dependencies", conflicts_with = "show_dependencies")]
        no_dependencies: bool,

        /// Maximum number of callers to display (default: 5)
        #[arg(long = "max-callers", default_value = "5")]
        max_callers: usize,

        /// Maximum number of callees to display (default: 5)
        #[arg(long = "max-callees", default_value = "5")]
        max_callees: usize,

        /// Show external crate calls in dependencies
        #[arg(long = "show-external-calls")]
        show_external: bool,

        /// Show standard library calls in dependencies
        #[arg(long = "show-std-lib-calls")]
        show_std_lib: bool,

        /// Explain metric definitions and formulas (measured vs estimated)
        #[arg(long = "explain-metrics")]
        explain_metrics: bool,

        /// Show verbose macro parsing warnings
        #[arg(long = "verbose-macro-warnings")]
        verbose_macro_warnings: bool,

        /// Show macro expansion statistics at the end of analysis
        #[arg(long = "show-macro-stats")]
        show_macro_stats: bool,

        /// Show pattern warnings for uncertain detections
        #[arg(long = "show-pattern-warnings")]
        show_pattern_warnings: bool,

        /// Validate LOC consistency across analysis modes (with/without coverage)
        #[arg(long = "validate-loc")]
        validate_loc: bool,

        /// Enable call graph debugging with detailed resolution information
        #[arg(long = "debug-call-graph")]
        debug_call_graph: bool,

        /// Trace specific functions during call resolution (comma-separated)
        #[arg(long = "trace-function", value_delimiter = ',')]
        trace_functions: Option<Vec<String>>,

        /// Show only call graph statistics (no detailed failure list)
        #[arg(long = "call-graph-stats")]
        call_graph_stats_only: bool,

        /// Debug output format (text or json)
        #[arg(long = "debug-format", value_enum, default_value = "text")]
        debug_format: DebugFormatArg,

        /// Validate call graph structure and report issues
        #[arg(long = "validate-call-graph")]
        validate_call_graph: bool,

        /// Show score breakdown for debugging (deprecated: use -v instead)
        #[arg(long = "explain-score", hide = true)]
        explain_score: bool,

        /// Enable profiling to identify performance bottlenecks (Spec 001).
        /// Outputs timing breakdown for each analysis phase when complete.
        #[arg(long = "profile", help_heading = "Profiling Options")]
        profile: bool,

        /// Write profiling data to file in JSON format (requires --profile).
        /// Use this for post-analysis performance investigation.
        #[arg(
            long = "profile-output",
            requires = "profile",
            help_heading = "Profiling Options"
        )]
        profile_output: Option<PathBuf>,
    },

    /// Initialize configuration file
    Init {
        /// Force overwrite existing config
        #[arg(short, long)]
        force: bool,
    },

    /// Validate code against thresholds
    Validate {
        /// Path to analyze
        path: PathBuf,

        /// Configuration file
        #[arg(short, long)]
        config: Option<PathBuf>,

        /// LCOV coverage file for risk analysis and score dampening.
        /// Coverage data dampens debt scores for well-tested code (multiplier = 1.0 - coverage),
        /// surfacing untested complex functions. Total debt score with coverage ≤ score without.
        #[arg(
            long = "coverage-file",
            visible_alias = "lcov",
            help_heading = "Coverage and Risk Analysis"
        )]
        coverage_file: Option<PathBuf>,

        /// Output format
        #[arg(short, long, value_enum)]
        format: Option<OutputFormat>,

        /// Output file (defaults to stdout)
        #[arg(short, long)]
        output: Option<PathBuf>,

        /// Enable context-aware risk analysis
        #[arg(
            long = "context",
            visible_alias = "enable-context",
            help_heading = "Coverage and Risk Analysis"
        )]
        enable_context: bool,

        /// Context providers to use (critical_path, dependency, git_history)
        #[arg(long = "context-providers", value_delimiter = ',')]
        context_providers: Option<Vec<String>>,

        /// Disable specific context providers
        #[arg(long = "disable-context", value_delimiter = ',')]
        disable_context: Option<Vec<String>>,

        /// Maximum debt density allowed (per 1000 LOC)
        #[arg(long = "max-debt-density")]
        max_debt_density: Option<f64>,

        /// Show only top N priority items
        #[arg(long = "top", visible_alias = "head")]
        top: Option<usize>,

        /// Show only bottom N priority items (lowest priority)
        #[arg(long = "tail")]
        tail: Option<usize>,

        /// Use summary format with tiered priority display (compact output)
        #[arg(long = "summary", short = 's')]
        summary: bool,

        /// Disable semantic analysis (fallback mode)
        #[arg(long = "semantic-off")]
        semantic_off: bool,

        /// Show score breakdown for debugging (deprecated: use -v instead)
        #[arg(long = "explain-score", hide = true)]
        explain_score: bool,

        /// Increase verbosity level (can be repeated: -v, -vv, -vvv)
        /// -v: Show main score factors
        /// -vv: Show detailed calculations
        /// -vvv: Show all debug information
        #[arg(short = 'v', long = "verbose", action = clap::ArgAction::Count)]
        verbosity: u8,

        /// Disable parallel processing (enabled by default).
        /// Parallel processing utilizes all CPU cores for call graph construction
        /// and unified analysis, providing 70-90% performance improvement on multi-core systems.
        /// Use this flag to force sequential processing for debugging or compatibility.
        #[arg(long = "no-parallel")]
        no_parallel: bool,

        /// Number of threads for parallel processing (0 = use all cores).
        /// Controls thread pool size for parallel call graph construction.
        /// Examples: --jobs 4 (use 4 threads), --jobs 0 (use all available cores).
        /// Environment variable DEBTMAP_JOBS can also be used to set this value.
        #[arg(long = "jobs", short = 'j', default_value = "0")]
        jobs: usize,

        /// Show detailed module split recommendations for god objects and large files.
        /// This experimental feature suggests how to decompose large files into
        /// smaller, focused modules. Hidden by default.
        #[arg(long = "show-splits")]
        show_splits: bool,
    },

    /// Compare two analysis results and generate diff
    Compare {
        /// Path to "before" analysis JSON
        #[arg(long, value_name = "FILE")]
        before: PathBuf,

        /// Path to "after" analysis JSON
        #[arg(long, value_name = "FILE")]
        after: PathBuf,

        /// Path to implementation plan (to extract target location)
        #[arg(long, value_name = "FILE")]
        plan: Option<PathBuf>,

        /// Target location (alternative to --plan)
        /// Format: file:function:line
        #[arg(long, value_name = "LOCATION", conflicts_with = "plan")]
        target_location: Option<String>,

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

        /// Output file (defaults to stdout)
        #[arg(short, long)]
        output: Option<PathBuf>,
    },

    /// Validate technical debt improvement from comparison results
    ValidateImprovement {
        /// Path to comparison JSON file from 'debtmap compare'
        #[arg(long, value_name = "FILE")]
        comparison: PathBuf,

        /// Output file path for validation results
        #[arg(
            long,
            short = 'o',
            value_name = "FILE",
            default_value = ".prodigy/debtmap-validation.json"
        )]
        output: PathBuf,

        /// Path to previous validation for progress tracking
        #[arg(long, value_name = "FILE")]
        previous_validation: Option<PathBuf>,

        /// Improvement threshold percentage (0-100)
        #[arg(long, default_value = "75.0")]
        threshold: f64,

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

        /// Suppress progress output (automation mode)
        #[arg(long, short = 'q')]
        quiet: bool,
    },

    /// Diagnose and validate LCOV coverage file
    DiagnoseCoverage {
        /// LCOV coverage file to diagnose
        coverage_file: PathBuf,
        /// Output format (text or json)
        #[arg(long, default_value = "text")]
        format: String,
    },

    /// Explain coverage detection for a specific function (debugging tool)
    ExplainCoverage {
        /// Path to the codebase to analyze
        path: PathBuf,

        /// LCOV coverage file
        #[arg(
            long = "coverage-file",
            visible_alias = "lcov",
            help_heading = "Coverage and Risk Analysis"
        )]
        coverage_file: PathBuf,

        /// Function name to explain (e.g., "create_auto_commit")
        #[arg(long = "function")]
        function_name: String,

        /// File path containing the function (optional, helps narrow search)
        #[arg(long = "file")]
        file_path: Option<PathBuf>,

        /// Show all attempted matching strategies
        #[arg(long = "verbose", short = 'v')]
        verbose: bool,

        /// Output format
        #[arg(short = 'f', long = "format", value_enum, default_value = "text")]
        format: DebugFormatArg,
    },
}

/// Output format options
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
pub enum OutputFormat {
    Json,
    /// Markdown format with comprehensive analysis (uses LLM-optimized writer)
    Markdown,
    Terminal,
    /// Graphviz DOT format for dependency visualization
    Dot,
}

/// Priority levels for debt items
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
pub enum Priority {
    Low,
    Medium,
    High,
    Critical,
}

impl From<Priority> for crate::core::Priority {
    fn from(p: Priority) -> Self {
        match p {
            Priority::Low => crate::core::Priority::Low,
            Priority::Medium => crate::core::Priority::Medium,
            Priority::High => crate::core::Priority::High,
            Priority::Critical => crate::core::Priority::Critical,
        }
    }
}

impl From<OutputFormat> for crate::io::output::OutputFormat {
    fn from(f: OutputFormat) -> Self {
        match f {
            OutputFormat::Json => crate::io::output::OutputFormat::Json,
            OutputFormat::Markdown => crate::io::output::OutputFormat::Markdown,
            OutputFormat::Terminal => crate::io::output::OutputFormat::Terminal,
            OutputFormat::Dot => crate::io::output::OutputFormat::Dot,
        }
    }
}

/// Parse CLI arguments using Clap
pub fn parse_args() -> Cli {
    Cli::parse()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_priority_conversion() {
        assert_eq!(
            crate::core::Priority::from(Priority::Low),
            crate::core::Priority::Low
        );
        assert_eq!(
            crate::core::Priority::from(Priority::Medium),
            crate::core::Priority::Medium
        );
        assert_eq!(
            crate::core::Priority::from(Priority::High),
            crate::core::Priority::High
        );
        assert_eq!(
            crate::core::Priority::from(Priority::Critical),
            crate::core::Priority::Critical
        );
    }

    #[test]
    fn test_output_format_conversion() {
        assert_eq!(
            crate::io::output::OutputFormat::from(OutputFormat::Json),
            crate::io::output::OutputFormat::Json
        );
        assert_eq!(
            crate::io::output::OutputFormat::from(OutputFormat::Markdown),
            crate::io::output::OutputFormat::Markdown
        );
        assert_eq!(
            crate::io::output::OutputFormat::from(OutputFormat::Terminal),
            crate::io::output::OutputFormat::Terminal
        );
    }

    #[test]
    fn test_cli_parsing_analyze_command() {
        use clap::Parser;

        let args = vec![
            "debtmap",
            "analyze",
            "/test/path",
            "--format",
            "json",
            "--threshold-complexity",
            "15",
            "--threshold-duplication",
            "100",
        ];

        let cli = Cli::parse_from(args);

        match cli.command {
            Commands::Analyze {
                path,
                format,
                threshold_complexity,
                threshold_duplication,
                ..
            } => {
                assert_eq!(path, PathBuf::from("/test/path"));
                assert_eq!(format, OutputFormat::Json);
                assert_eq!(threshold_complexity, 15);
                assert_eq!(threshold_duplication, 100);
            }
            _ => panic!("Expected Analyze command"),
        }
    }

    #[test]
    fn test_cli_parsing_init_command() {
        use clap::Parser;

        let args = vec!["debtmap", "init", "--force"];

        let cli = Cli::parse_from(args);

        match cli.command {
            Commands::Init { force } => {
                assert!(force);
            }
            _ => panic!("Expected Init command"),
        }
    }

    #[test]
    fn test_cli_parsing_validate_command() {
        use clap::Parser;

        let args = vec![
            "debtmap",
            "validate",
            "/test/path",
            "--config",
            "/config/path",
        ];

        let cli = Cli::parse_from(args);

        match cli.command {
            Commands::Validate { path, config, .. } => {
                assert_eq!(path, PathBuf::from("/test/path"));
                assert_eq!(config, Some(PathBuf::from("/config/path")));
            }
            _ => panic!("Expected Validate command"),
        }
    }

    #[test]
    fn test_priority_ordering() {
        assert!(Priority::Low < Priority::Medium);
        assert!(Priority::Medium < Priority::High);
        assert!(Priority::High < Priority::Critical);
    }

    #[test]
    fn test_output_format_equality() {
        assert_eq!(OutputFormat::Json, OutputFormat::Json);
        assert_ne!(OutputFormat::Json, OutputFormat::Markdown);
        assert_ne!(OutputFormat::Terminal, OutputFormat::Json);
    }

    #[test]
    fn test_parse_args_wrapper() {
        use clap::Parser;

        let test_args = vec!["debtmap", "analyze", "."];
        let cli = Cli::parse_from(test_args);

        match cli.command {
            Commands::Analyze { .. } => {}
            _ => panic!("Expected Analyze command from test args"),
        }
    }

    #[test]
    fn test_no_multi_pass_flag() {
        use clap::Parser;

        let args = vec!["debtmap", "analyze", ".", "--no-multi-pass"];
        let cli = Cli::parse_from(args);

        match cli.command {
            Commands::Analyze { no_multi_pass, .. } => {
                assert!(no_multi_pass);
            }
            _ => panic!("Expected Analyze command"),
        }
    }

    #[test]
    fn test_default_enables_multi_pass() {
        use clap::Parser;

        let args = vec!["debtmap", "analyze", "."];
        let cli = Cli::parse_from(args);

        match cli.command {
            Commands::Analyze { no_multi_pass, .. } => {
                assert!(!no_multi_pass);
            }
            _ => panic!("Expected Analyze command"),
        }
    }

    #[test]
    fn test_streaming_flag() {
        use clap::Parser;

        let args = vec!["debtmap", "analyze", ".", "--streaming"];
        let cli = Cli::parse_from(args);

        match cli.command {
            Commands::Analyze {
                streaming,
                stream_to,
                ..
            } => {
                assert!(streaming);
                assert!(stream_to.is_none());
            }
            _ => panic!("Expected Analyze command"),
        }
    }

    #[test]
    fn test_streaming_with_stream_to() {
        use clap::Parser;

        let args = vec![
            "debtmap",
            "analyze",
            ".",
            "--streaming",
            "--stream-to",
            "output.jsonl",
        ];
        let cli = Cli::parse_from(args);

        match cli.command {
            Commands::Analyze {
                streaming,
                stream_to,
                ..
            } => {
                assert!(streaming);
                assert_eq!(stream_to, Some(PathBuf::from("output.jsonl")));
            }
            _ => panic!("Expected Analyze command"),
        }
    }

    #[test]
    fn test_streaming_default_off() {
        use clap::Parser;

        let args = vec!["debtmap", "analyze", "."];
        let cli = Cli::parse_from(args);

        match cli.command {
            Commands::Analyze { streaming, .. } => {
                assert!(!streaming);
            }
            _ => panic!("Expected Analyze command"),
        }
    }
}
