use std::env;
use std::process;

fn main() {
    let mut command = String::new();
    let mut command_args = Vec::<String>::new();
    for (i, arg) in env::args().enumerate() {
        match i {
            0 => continue,
            1 => {
                command = arg;
                continue;
            }
            _ => command_args.push(arg.clone()),
        }
    }

    match command.as_str() {
        "tc" => {
            if command_args.len() < 1 {
                eprintln!("ERROR: missing a value to convert");
                process::exit(1);
            }
            temp_convert(&command_args[0])
        }
        "fib" => {
            if command_args.len() < 1 {
                eprintln!("ERROR: missing a value to fib");
                process::exit(1);
            }
            let n: u64 = command_args[0]
                .parse()
                .expect("could not parse value to fib");
            if n >= 40 {
                eprintln!("WARN: this might take a while");
            }
            fib_n(n)
        }
        "rx" => redefine_x(),
        "help" => show_help(),
        _ => {
            show_help();
            eprintln!("ERROR: missing sub-command");
            process::exit(1);
        }
    }
}

fn show_help() {
    println!("Usage: variables <command> [command_args]");
    println!();
    println!("The value for <command> may be one of:");
    println!("  fib - generate Nth Fibonacci number");
    println!("  tc  - convert temperatures between Fahrenheit and Celsius");
    println!("  rx  - redefine x");
    println!();
}

fn redefine_x() {
    let mut x = 5;
    println!("The value of x is: {}", x);
    x = 6;
    println!("The value of x is: {}", x);
}

fn temp_convert(to_convert: &str) {
    let to_convert = to_convert.to_lowercase();
    if to_convert.ends_with("c") {
        let c: f32 = to_convert
            .trim_end_matches('c')
            .parse()
            .expect("failed to parse temperature");
        println!("{}F", temp_convert_c2f(c));
    } else if to_convert.ends_with("f") {
        let f: f32 = to_convert
            .trim_end_matches('f')
            .parse()
            .expect("failed to parse temperature");
        println!("{}C", temp_convert_f2c(f));
    } else {
        eprintln!("ERROR: What are we supposed to do to {:?}?", to_convert);
    }
}

fn temp_convert_c2f(c: f32) -> f32 {
    (c * (9.0 / 5.0)) + 32.0
}

fn temp_convert_f2c(f: f32) -> f32 {
    (f - 32.0) * (5.0 / 9.0)
}

fn fib_n(n: u64) {
    println!("{}", fib_up_to(n));
}

fn fib_up_to(n: u64) -> u64 {
    match n {
        0 => 0,
        1 => 1,
        _ => fib_up_to(n - 1) + fib_up_to(n - 2),
    }
}
