use crate::{
    commands::{Cli, Config, Result},
    print_tip,
    templates::*,
};
use clap::Parser;
use color_print::cprintln;
use std::fs::OpenOptions;

use crate::database::Database;

/// Initialize a new database or re-initialize an existing one.
///
/// Creates (or replaces) a database file (JSON) named jobber.json beside the
/// configuration file.
/// The filename can be changed by using `jobber -f <FILENAME> init`.
///
/// This function can be undone with `jobber undo`.
#[derive(Parser, Debug)]
pub(crate) struct Init {
    /// What to initialize (database or templates)
    #[clap(default_value = "database")]
    what: String,
}

impl Init {
    pub(crate) fn run(&self, cli: &Cli) -> Result<()> {
        let file_name = &Config::load()?.database_path()?;
        match self.what.to_lowercase().as_str() {
            "database" => {
                let file_exists = file_name.exists();
                if file_exists {
                    cli.backup_database()?;
                }
                let file = OpenOptions::new()
                    .write(true)
                    .create(true)
                    .truncate(true)
                    .open(file_name)?;
                let database = Database::default();
                serde_json::to_writer_pretty(file, &database)?;
                if file_exists {
                    cprintln!(
                        "Successfully recreated database file <s>{}</>.",
                        file_name.to_string_lossy()
                    );
                    print_tip!(cli);
                    print_tip!(cli, "Use <s>jobber undo</> to get back the old database.");
                } else {
                    cprintln!(
                        "Successfully created new database file <s>{}</>",
                        file_name.to_string_lossy()
                    );
                    print_tip!(cli);
                    print_tip!(
                        cli,
                        "Use <s>jobber create company</> to set your company information."
                    );
                }
                print_tip!(
                    cli,
                    "Use <s>jobber init templates</> to install standard templates."
                );
                Ok(())
            }
            "templates" => {
                default_::TEMPLATE.iter().try_for_each(init_file)?;
                marx_and_friends::TEMPLATE.iter().try_for_each(init_file)?;
                Ok(())
            }
            _ => todo!("error"),
        }
    }
}

fn init_file(template: &(&str, &[u8])) -> Result<()> {
    let path = Config::load()?
        .database_path()?
        .parent()
        .expect("invalid data path")
        .join(template.0);
    std::fs::create_dir_all(path.parent().expect("invalid data path"))?;
    Ok(std::fs::write(path, template.1)?)
}
