use std::env;
use std::error;

use config_diag::ConfigDiag;
use expect_exit::ExpectedWithError;

#[macro_use]
extern crate quick_error;

use fcheck_testdata::defs;

const USAGE: &str = "Usage: fcheck-data [-v] -f data -o output template
\t-f\tthe path to the JSON test data file
\t-o\tthe path to the output file to generate
\t-v\tverbose operation; display diagnostic output";

quick_error! {
    #[derive(Debug)]
    pub enum CommandLineError {
        SingleArg {
            display("A single template path argument expected\n{}", USAGE)
        }
    }
}

fn parse_args() -> Result<defs::Config, Box<dyn error::Error>> {
    let args: Vec<String> = env::args().collect();
    let mut optargs = getopts::Options::new();

    optargs.reqopt("f", "data-file", "the JSON test data", "DATA_FILE");
    optargs.reqopt("o", "output", "the file to generate", "OUTPUT_PATH");
    optargs.optflag(
        "v",
        "verbose",
        "verbose operation; display diagnostic output",
    );
    let opts = optargs.parse(&args[1..])?;

    let template_path = match opts.free.len() {
        1 => opts.free[0].to_string(),
        _ => return Err(Box::new(CommandLineError::SingleArg)),
    };

    Ok(defs::Config {
        data_path: opts.opt_str("f").unwrap(),
        output_path: opts.opt_str("o").unwrap(),
        template_path,
        verbose: opts.opt_present("v"),
    })
}

fn main() {
    let cfg = parse_args().or_exit_e_("Error parsing the command line");
    let template = fcheck_testdata::parse::parse_template(&cfg)
        .or_exit_e(|| format!("Error parsing the {} template", cfg.template_path));
    let test_data = fcheck_testdata::parse::parse_test_data(&cfg)
        .or_exit_e(|| format!("Error parsing the {} data file", cfg.data_path));
    fcheck_testdata::output::write_output_file(&cfg, template, test_data)
        .or_exit_e_("Error generating the output file");
    cfg.diag_("Everything seems fine!");
}
