#[macro_use]
use clap::Parser;
use libduralumin::passphrase_gen::{PassPhraseGenerator, Words};

/// program that generates random passphrases.
#[derive(Parser)]
#[clap(
    name = "duralumin",
    version = "0.1.0",
    author = "No One <noonebtw@nirgendwo.xyz>"
)]
struct Opts {
    #[clap(short = 'l', long)]
    num_words: Option<i16>,
    #[clap(long)]
    capitalize: Option<bool>,
    #[clap(long)]
    min_word_length: Option<i16>,
    #[clap(short, long)]
    count: Option<i16>,
    #[clap(long, default_value = "useapassphrase")]
    backend: String,
}

impl Opts {
    /// gets the number of words per passphrase
    pub fn words_per_passphrase(&self) -> i16 {
        self.num_words.unwrap_or(6)
    }

    /// should the first letter of each word be capitalized?
    pub fn capitalize(&self) -> bool {
        self.capitalize.unwrap_or(false)
    }

    /// gets the number of passphrases to generate
    pub fn passphrase_count(&self) -> i16 {
        self.count.unwrap_or(5)
    }

    /// which source to use for words
    pub fn backend(&self) -> Option<Backend> {
        Backend::from_str(&self.backend)
    }
}

enum Backend {
    UseAPassPhrase,
    EnglishWords,
}

impl Backend {
    pub fn from_str<S>(s: S) -> Option<Self>
    where
        S: AsRef<str>,
    {
        match s.as_ref() {
            "useapassphrase" => Some(Backend::UseAPassPhrase),
            "english" => Some(Backend::EnglishWords),
            _ => None,
        }
    }
}

fn main() {
    let opts = Opts::parse();
    let gen = PassPhraseGenerator::new()
        .with_capitalized(opts.capitalize())
        .with_min_word_length(opts.min_word_length)
        .with_length(opts.words_per_passphrase());

    let words = match opts.backend() {
        Some(Backend::UseAPassPhrase) => Words::from_str(include_str!("../../useapassphrase.txt")),
        Some(Backend::EnglishWords) => Words::from_str(include_str!("../../words_alpha.txt")),
        None => {
            panic!("invalid backend.")
        }
    };

    for passphrase in gen
        .generate_n(&words, opts.passphrase_count() as usize)
        .expect("failed to generate passphrases. this is bad.")
    {
        println!("{}", passphrase);
    }
}
