use crate::{config, delete, import};
use clap::{Parser, Subcommand, ValueEnum};
use hagrid_database::Query;
use std::path::PathBuf;

#[derive(Parser)]
#[command(version, about, long_about = None, help_expected = true)]
pub(crate) struct Cli {
    #[arg(
        short = 'c',
        long = "config",
        default_value = "Rocket.toml",
        global = true
    )]
    /// Sets a custom config file
    file: PathBuf,

    #[arg(short = 'e', long = "environment", value_enum, value_name = "ENVIRONMENT", default_value_t = DeploymentEnvironment::Production, global = true)]
    /// Specify section of configuration to use. Usually coupled to deployment environment name
    env: DeploymentEnvironment,

    #[command(subcommand)]
    command: Command,
}

#[derive(Subcommand)]
enum Command {
    /// Delete (address, key)-binding(s), and/or a key(s).
    Delete {
        #[arg(long)]
        /// Also delete all bindings.
        all_bindings: bool,

        #[arg(long)]
        /// Also delete all bindings and the key.
        all: bool,

        /// E-Mail address, Fingerprint, or KeyID of the TPK to delete.
        /// If a Fingerprint or KeyID is given, --all is implied.
        query: Query,
    },
    /// Import keys into Hagrid
    Import {
        #[arg(required = true)]
        /// List of keyring files to import
        keyring_files: Vec<PathBuf>,
    },
}

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
pub(crate) enum DeploymentEnvironment {
    #[value(alias = "prod")]
    Production,
    #[value(alias = "stage")]
    Staging,
    #[value(alias = "dev")]
    Development,
}

pub(crate) fn dispatch_cmd(cli: &Cli) -> anyhow::Result<()> {
    let keys_db_internal_dir = config::load(&cli.file, cli.env)?
        .keys_internal_dir
        .unwrap()
        .canonicalize()?;

    match &cli.command {
        Command::Delete {
            query,
            all_bindings,
            all,
        } => delete::run(keys_db_internal_dir, query, *all_bindings, *all),
        Command::Import { keyring_files } => {
            import::run(keys_db_internal_dir, keyring_files.to_owned())
        }
    }
}

pub(crate) fn print_errors(e: anyhow::Error) {
    eprint!("{}", e);
    let mut cause = e.source();
    while let Some(c) = cause {
        eprint!(":\n  {}", c);
        cause = c.source();
    }
    eprintln!();
}

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

    #[test]
    fn test_cli() {
        Cli::command().debug_assert()
    }
}
