use anyhow::{anyhow, bail, Result};
use chanora_resolver::{run, setup_log, Args};

const DEFAULT_SERVICE: &str = "ts3";

#[tokio::main]
async fn main() {
    setup_log();

    if let Err(err) = execute(std::env::args().skip(1)).await {
        tracing::error!(err = %err, "lookup failed");
        std::process::exit(1);
    }
}

async fn execute<I, S>(args: I) -> Result<()>
where
    I: IntoIterator<Item = S>,
    S: Into<String>,
{
    let parsed = parse_args(args)?;
    run(parsed).await
}

fn parse_args<I, S>(args: I) -> Result<Args>
where
    I: IntoIterator<Item = S>,
    S: Into<String>,
{
    let mut host = String::new();
    let mut service = DEFAULT_SERVICE.to_string();
    let mut protocol = String::new();

    let mut iter = args.into_iter().map(Into::into).peekable();
    while let Some(arg) = iter.next() {
        match arg.as_str() {
            "-h" | "--help" => {
                print_help();
                std::process::exit(0);
            }
            "-host" | "--host" => {
                host = next_value(&mut iter, "host")?;
            }
            "-service" | "--service" => {
                service = next_value(&mut iter, "service")?;
            }
            "-protocol" | "--protocol" => {
                protocol = next_value(&mut iter, "protocol")?;
            }
            value if value.starts_with('-') => {
                bail!("unknown flag: {value}");
            }
            value => {
                bail!("unexpected positional argument: {value}");
            }
        }
    }

    Ok(Args {
        host,
        service,
        protocol,
    })
}

fn next_value<I>(iter: &mut std::iter::Peekable<I>, flag: &str) -> Result<String>
where
    I: Iterator<Item = String>,
{
    iter.next()
        .ok_or_else(|| anyhow!("missing value for {flag} flag"))
}

fn print_help() {
    println!("chanora-resolver -host <host> -service <dns|ts3|tsdns|nick> -protocol <udp|tcp>");
}

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

    #[test]
    fn parse_args_supports_flag_pairs() {
        let args = parse_args([
            "-host",
            "Example.com",
            "-service",
            "dns",
            "-protocol",
            "udp",
        ])
        .unwrap();
        assert_eq!(
            args,
            Args {
                host: "Example.com".into(),
                service: "dns".into(),
                protocol: "udp".into(),
            }
        );
    }
}
