use crate::db::Database;
use crate::identity::{IdKeyData, Identity};
use age::secrecy::ExposeSecret;
use regex::Regex;
use std::path::Path;
use std::process::exit;

pub fn create_id(db_path: &Path, name: String, email: String) -> anyhow::Result<()> {
    let mut db = Database::load_or_create(db_path)?;

    // sanity check to ensure this id does not already exist
    for key in &db.keys {
        if key.name == name && key.email == email {
            eprintln!(
                "key '{:?}' (keyid {}) already exists  in database",
                key,
                key.keys.keyid()?
            );
            eprintln!("if you want to recreate it, remove it first");
            exit(1);
        }
    }

    // Email is a fucking nightmare
    // RFC5322, I hate you
    let email_re = Regex::new(
        r#"(?x)
            ^(?P<login>[^@\s]+)@
            ([[:word:]]+\.)*
            [[:word:]]+$
            "#,
    )
    .unwrap();

    if !email_re.is_match(&email) {
        eprintln!("`{email}` is not a valid RFC5322 email address");
        exit(1);
    }

    let key = age::x25519::Identity::generate();
    let ss = key.to_string();
    let ss = ss.expose_secret();

    let identity = Identity {
        name,
        email,
        keys: IdKeyData::Local(ss.to_string()),
    };

    db.keys.push(identity.clone());
    // save database
    db.write(db_path)?;

    println!(
        "wrote new key {:?} (keyid {}) to database",
        identity,
        identity.keys.keyid()?
    );

    Ok(())
}
