use anyhow::Result;
use promptly::prompt_opt;
use text_io::read;

pub fn is_it_yes(prompt: &str) -> bool {
    loop {
        print!("{prompt}");
        let response: String = read!();
        let response = response.to_lowercase();
        match response.trim() {
            "y" | "yes" => return true,
            "n" | "no" => return false,
            _ => {
                println!("I don't understand your answer; please enter 'y' or 'n'!")
            }
        }
    }
}

pub fn get_natural_number(prompt: &str) -> Result<Option<usize>> {
    if !prompt.is_empty() {
        print!("{prompt}");
    }
    let input: String = read!();
    match input.to_lowercase().trim() {
        "x" | "q" => Ok(None),
        s => {
            let n: usize = s.parse()?;
            Ok(Some(n))
        }
    }
}

pub fn parse_natural_numbers<S: Into<String>>(input: S) -> Result<Vec<usize>> {
    let input = input.into();
    let s = input.split(",");
    let result: Result<Vec<_>> = s
        .map(|n| n.trim())
        .filter(|n| !n.is_empty())
        .map(|n| n.parse::<usize>().map_err(|e| e.into()))
        .collect();
    Ok(result?)
}

pub fn _get_natural_numbers(prompt: &str) -> Result<Vec<usize>> {
    let input: Option<String> = prompt_opt(prompt)?;
    if let Some(input) = input.map(|s| s.trim().to_lowercase()) {
        if input != "x" && input != "q" {
            return parse_natural_numbers(input);
        }
    }
    Ok(Vec::new())
}

pub fn get_command(prompt: &str) -> (Option<String>, Option<String>) {
    let response: Option<String> = prompt_opt(prompt).unwrap();
    if let Some(response) = response {
        let response = response.to_lowercase();
        let mut responses = response.trim().split_whitespace();
        let command = responses.next().map(|c| c.to_string());
        let parameter = responses.next().map(|c| c.to_string());
        let parameters = if let Some(parameter) = parameter {
            // TODO: Use Itertools::join
            Some(responses.fold(parameter, |a, s| format!("{a} {s}")))
        } else {
            None
        };
        return (command, parameters);
    }
    (None, None)
}

#[macro_export]
macro_rules! dprint {
    ($($arg:tt)*) => {
        {
            if *crate::DEBUG.get().unwrap_or(&false) {
                eprint!($($arg)*)
            }
        }
    };
}

pub fn plural(n: u32) -> &'static str {
    if n > 1 {
        "s"
    } else {
        ""
    }
}