use crate::cmds::createid::create_id;
use crate::db::db_default;
use crate::wrapper::wrapper;
use std::process::exit;

mod cmds;
mod db;
mod identity;
mod wrapper;

fn main() -> anyhow::Result<()> {
    let mut pargs = pico_args::Arguments::from_env();

    if pargs.contains(["-h", "--help"]) {
        print_help();
        exit(0);
    }

    let database = pargs
        .opt_value_from_str(["-D", "--database"])?
        .unwrap_or(db_default());

    let Some(subcommand) = pargs.subcommand()? else {
        // run the wrapper
        return wrapper(pargs, &database);
    };

    match subcommand.as_str() {
        "create-id" => {
            let Ok(name) = pargs.free_from_str() else {
                eprintln!("name is required, --help for help");
                exit(1);
            };
            let Ok(email) = pargs.free_from_str() else {
                eprintln!("email is required, --help for help");
                exit(1);
            };

            create_id(&database, name, email)?;
        }
        "ls" => {
            cmds::ls::list_keys(
                &database,
                pargs.contains(["-l", "--local"]),
                pargs.contains(["-p", "--peer"]),
                pargs.contains(["-f", "--full"]),
            )?;
        }
        "show" => {
            let Ok(search) = pargs.free_from_str() else {
                eprintln!("search term is required, --help for help");
                exit(1);
            };
            cmds::show::show_key(&database, search, pargs.contains(["-e", "--expose-secret"]))?;
        }
        "import" => {
            let Ok(key) = pargs.free_from_str() else {
                eprintln!("key is required, --help for help");
                exit(1);
            };
            cmds::import::import_key(&database, key, pargs.contains(["-i", "--import-anyway"]))?;
        }
        unknown => {
            eprintln!("Unknown subcommand: {}", unknown);
            print_help();
            exit(1);
        }
    }

    Ok(())
}

fn print_help() {
    let cf = db_default().display().to_string();
    println!("{}", HELP.to_string().replace("{CONFIGFILE}", cf.as_str()));
}
const HELP: &str = "\
sage - simple age wrapper for named identities

USAGE:
    sage [OPTIONS] [SUBCOMMAND]
    sage [--encrypt] (-r RECIPIENT | -R PATH)... [--armor] [-o OUTPUT] [INPUT]
    sage [--encrypt] --passphrase [--armor] [-o OUTPUT] [INPUT]
    sage --decrypt [-i PATH]... [-o OUTPUT] [INPUT]

OPTIONS:
    -h, --help                  Prints help information
    -D, --database <FILE>       Set the database file (default {CONFIGFILE})

    -v, --verbose               Enable debug logging
    -e, --encrypt               Encrypt the input to the output. Default if omitted.
    -d, --decrypt               Decrypt the input to the output.
    -o, --output OUTPUT         Write the result to the file at path OUTPUT.
    -a, --armor                 Encrypt to a PEM encoded format.
    -p, --passphrase            Encrypt with a passphrase.
    -r, --recipient RECIPIENT   Encrypt to the specified RECIPIENT. Can be repeated.
    -R, --recipients-file PATH  Encrypt to the recipients listed at PATH. Can be repeated.
    -i, --identity IDENTITY     Use the specified identity. Can be repeated.

INPUT defaults to standard input, and OUTPUT defaults to standard output.
If OUTPUT exists, it will be overwritten.

RECIPIENT can be an age public key generate by age-keygen (\"age1...\")
an SSH public key (\"ssh-ed25519 AAAA...\", \"ssh-rsa AAAA...\"), OR
a fuzzy search term to use the database to locate a key.

Recipient files contain one or more recipients, one per line. Empty lines
and lines starting with \"#\" are ignored as comments. \"-\" may be uised to
read recipients from standard input.

An IDENTITY may either be a fuzzy search term to search the database, or
an identity file.

Identity files contain one or more secret keys (\"AGE-SECRET-KEY-1...\"),
one per line, or an SSH key. Empty lines and lines starting with \"#\" are
ignored as comments. Passphrase encrypted age files can be used as
identity files. Multiple key files can be provided, and any unused ones
will be ignored. \"-\" may be used to read identities from standard input.

When --encrypt is specified explicitly, -i can also be used to encrypt to an
identity file symmetrically, instead or in addition to normal recipients.

If decrypting and an identity is omitted, all local identities will be used.

SUBCOMMANDS:

create-id <name> <email>
    Create a new local identity in the database.
    <name>      Name for the new identity
    <email>     Email of the new identity

ls [OPTIONS]
    List keys in the database
    OPTIONS:

    -l, --local     Show only local (your) keys
    -p, --peer      Show only peer (other's) keys
    -f, --full      List full public keys instead of key IDs

show [OPTIONS] <search term>
    Search the database (fuzzy) and show a specific key

    OPTIONS:
    -e, --expose-secret     Output the secret key, if it is a local key

import [OPTIONS] <key>
    Imports the provided key into the database.
    If the keyid already exists, it will do nothing.

    OPTIONS:
    -i, --insert-anyway     Insert even if a matching identity is already present
";
