regy 0.1.0

Private-by-default desktop agent for the Regy web interface
use std::path::PathBuf;

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

#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub(crate) enum OutputMode {
    #[default]
    Human,
    Json,
}

#[derive(Debug, Parser)]
#[command(
    name = "regy-pc-agent",
    version,
    about = "Configure and run the Regy PC Agent"
)]
pub(crate) struct CliArgs {
    #[arg(long, global = true)]
    pub json: bool,
    #[arg(long, global = true)]
    pub non_interactive: bool,
    #[arg(long, global = true)]
    pub yes: bool,
    #[arg(long, global = true)]
    pub config: Option<PathBuf>,
    #[command(subcommand)]
    pub command: Option<CliCommand>,
}

impl CliArgs {
    pub(crate) fn output_mode(&self) -> OutputMode {
        if self.json {
            OutputMode::Json
        } else {
            OutputMode::Human
        }
    }
}

#[derive(Debug, Subcommand)]
pub(crate) enum CliCommand {
    Setup,
    Start(StartArgs),
    Stop,
    Status,
    Configure(ConfigureArgs),
    Doctor,
}

#[derive(Debug, Args)]
pub(crate) struct ConfigureArgs {
    #[command(subcommand)]
    pub command: Option<ConfigureCommand>,
}

#[derive(Debug, Subcommand)]
pub(crate) enum ConfigureCommand {
    Clients(ClientsArgs),
}

#[derive(Debug, Args)]
pub(crate) struct ClientsArgs {
    #[command(subcommand)]
    pub command: ClientCommand,
}

#[derive(Debug, Subcommand)]
pub(crate) enum ClientCommand {
    List,
    Revoke { client_id: crate::pairing::ClientId },
}

#[derive(Debug, Default, Args)]
pub(crate) struct StartArgs {
    #[arg(short = 'd', long = "detach", conflicts_with = "daemon_child")]
    detach: bool,
    #[arg(long = "daemon-child", hide = true, conflicts_with = "detach")]
    daemon_child: bool,
    #[arg(
        long = "local",
        hide = true,
        num_args = 0..=1,
        default_missing_value = "removed",
        value_parser = reject_retired_start_mode_flag
    )]
    _retired_local: Option<String>,
    #[arg(
        long = "public",
        hide = true,
        num_args = 0..=1,
        default_missing_value = "removed",
        value_parser = reject_retired_start_mode_flag
    )]
    _retired_public: Option<String>,
}

impl StartArgs {
    pub(crate) const fn detach(&self) -> bool {
        self.detach
    }

    pub(crate) const fn daemon_child(&self) -> bool {
        self.daemon_child
    }
}

fn reject_retired_start_mode_flag(_value: &str) -> Result<String, String> {
    Err("--local/--public were removed; regy-pc-agent start is Iroh-only".into())
}