use clap::{Args, Parser, Subcommand};
use crate::speedtest::TestDuration;
#[derive(Parser)]
#[command(
name = "nd300",
author,
version,
disable_version_flag = true,
about = "ND-300 Network Diagnostic - QubeTX Developer Tools",
long_about = "ND-300 Network Diagnostic - QubeTX Developer Tools\n\n\
Cross-platform network diagnostics with 25+ concurrent checks,\n\
multi-stage network repair, and DNS configuration management.",
after_long_help = "EXAMPLES:\n\
\x20 nd300 Run standard diagnostics\n\
\x20 nd300 -t Technician mode (deep diagnostics)\n\
\x20 nd300 dns Change DNS servers and verify connectivity\n\
\x20 nd300 -d Same as 'nd300 dns' (legacy flag form)\n\
\x20 nd300 fix Diagnostic-driven triage and recovery loop\n\
\x20 nd300 -f Same as 'nd300 fix' (legacy flag form)\n\
\x20 nd300 update Check for updates and install\n\
\x20 nd300 clear-dns Reset DNS cache\n\
\x20 nd300 uninstall Remove nd300 from this system\n\
\x20 nd300 --fast Skip speed test for faster execution\n\
\x20 nd300 --json Output results as JSON\n\n\
Run 'nd300 --help' for full details, or 'nd300 -h' for a summary."
)]
pub struct Nd300Cli {
#[arg(
short = 't',
long = "tech",
alias = "technician",
help_heading = "Modes",
global = true
)]
pub tech: bool,
#[arg(short = 'T', long, help_heading = "Modes", global = true)]
pub title: Option<String>,
#[arg(long, help_heading = "Output", global = true)]
pub json: bool,
#[arg(long, help_heading = "Output", global = true)]
pub ascii: bool,
#[arg(long, help_heading = "Output", global = true)]
pub no_color: bool,
#[arg(long, help_heading = "Output", global = true)]
pub verbose: bool,
#[arg(long, help_heading = "Speed Test", global = true)]
pub fast: bool,
#[arg(long, default_value = "10", help_heading = "Speed Test", global = true)]
pub speed_duration: u64,
#[arg(short = 'd', long = "dns", help_heading = "Actions")]
pub dns: bool,
#[arg(short = 'f', long = "fix", help_heading = "Actions")]
pub fix: bool,
#[arg(short = 'c', long = "clear-dns", help_heading = "Actions")]
pub clear_dns: bool,
#[arg(long = "uninstall", help_heading = "Actions")]
pub uninstall: bool,
#[arg(long = "update", help_heading = "Actions")]
pub update: bool,
#[arg(
short = 'y',
long = "yes",
alias = "non-interactive",
help_heading = "Actions",
global = true
)]
pub yes: bool,
#[arg(short = 'v', long = "version", action = clap::ArgAction::Version)]
pub version: (),
#[command(subcommand)]
pub command: Option<Nd300Command>,
}
#[derive(Subcommand, Debug, Clone)]
pub enum Nd300Command {
Fix(FixArgs),
Dns,
Update,
#[command(name = "clear-dns")]
ClearDns,
Uninstall,
#[command(name = "migrate-cleanup", hide = true)]
MigrateCleanup(MigrateArgs),
}
#[derive(Args, Debug, Clone, Default)]
pub struct FixArgs {}
#[derive(Args, Debug, Clone, Default)]
pub struct MigrateArgs {
#[arg(long = "cargo-copy")]
pub cargo_copy: bool,
#[arg(long = "other-edition")]
pub other_edition: bool,
#[arg(long = "quiet")]
pub quiet: bool,
#[arg(long = "dry-run")]
pub dry_run: bool,
#[arg(long = "json")]
pub json: bool,
#[arg(long = "user-profile", value_name = "PATH")]
pub user_profile: Option<String>,
#[arg(long = "cargo-home", value_name = "PATH")]
pub cargo_home: Option<String>,
}
#[derive(Parser)]
#[command(
name = "speedqx",
author,
version,
disable_version_flag = true,
about = "SpeedQX Internet Speed Test - QubeTX Developer Tools",
long_about = "SpeedQX Internet Speed Test - QubeTX Developer Tools\n\n\
Quad-provider speed test using Cloudflare, M-Lab NDT7, LibreSpeed, and fast.com (Netflix).\n\
All four providers run and results are aggregated for maximum accuracy.",
after_long_help = "EXAMPLES:\n\
\x20 speedqx Run full speed test (all 4 providers)\n\
\x20 speedqx --duration 60 60s per direction for CF/NDT7/LS\n\
\x20 speedqx --fastcom-duration 30 Override fast.com to 30s/dir\n\
\x20 speedqx update Check for updates and install\n\
\x20 speedqx --update Same as 'speedqx update' (legacy flag form)\n\
\x20 speedqx --json Output results as JSON\n\n\
Run 'speedqx --help' for full details, or 'speedqx -h' for a summary."
)]
pub struct SpeedQXCli {
#[arg(long, help_heading = "Output", global = true)]
pub json: bool,
#[arg(long, help_heading = "Output", global = true)]
pub ascii: bool,
#[arg(long, help_heading = "Output", global = true)]
pub no_color: bool,
#[arg(
long,
default_value = "30",
value_parser = parse_duration,
help_heading = "Speed Test"
)]
pub duration: TestDuration,
#[arg(
long,
default_value = "auto",
value_parser = parse_duration,
help_heading = "Speed Test"
)]
pub fastcom_duration: TestDuration,
#[arg(long, default_value = "20", help_heading = "Speed Test")]
pub latency_probes: u32,
#[arg(long = "update", help_heading = "Actions")]
pub update: bool,
#[arg(short = 'v', long = "version", action = clap::ArgAction::Version)]
pub version: (),
#[command(subcommand)]
pub command: Option<SpeedQXCommand>,
}
#[derive(Subcommand, Debug, Clone)]
pub enum SpeedQXCommand {
Update,
}
fn parse_duration(s: &str) -> Result<TestDuration, String> {
if s.eq_ignore_ascii_case("auto") {
Ok(TestDuration::Auto)
} else {
s.parse::<u64>()
.map(TestDuration::Seconds)
.map_err(|_| format!("invalid duration '{}': expected a number or \"auto\"", s))
}
}