use std::fs::File;
use std::io::Write;
use std::os::unix::prelude::PermissionsExt;
use std::{
    path::PathBuf,
    process::{exit, Command},
};

/// Function used to get the git hooks repository
fn get_hooks_folder() -> PathBuf {
    let output = Command::new("git")
        .arg("rev-parse")
        .arg("--show-cdup")
        .output()
        .unwrap();
    match output.status.code().unwrap() {
        128 => {
            eprintln!("Not a git repository !");
            exit(128);
        }
        127 => {
            eprintln!("Git not found !");
            exit(127);
        }
        0 => (),
        num => {
            eprintln!("{}", String::from_utf8(output.stderr).unwrap());
            exit(num)
        }
    }
    let mut string_path = String::from_utf8(output.stdout).unwrap();
    if string_path.ends_with('\n') {
        string_path.pop();
    }
    let mut p = PathBuf::from(&string_path);
    p.push(".git");
    p.push("hooks");
    if !p.is_dir() {
        eprintln!("Folder {} not found !", p.to_str().unwrap());
        exit(5);
    }
    p
}

/// Function used to create a file
///
/// # Arguments:
/// * `folder`: The folder where the file will be created
/// * `file_name`: The file name of the file to create
/// * `content`: The content of the file to create
fn create_file(folder: &PathBuf, file_name: &str, content: &str) {
    let mut hfile = folder.to_owned();
    hfile.push(file_name);
    if hfile.is_file() {
        eprintln!(
            "Warning: The file {} already exists. Skipping...",
            hfile.to_str().unwrap()
        );
        return ();
    }
    let mut file = File::create(&hfile).unwrap_or_else(|e| {
        eprintln!(
            "Unable to create the file {}.\n{}",
            hfile.to_str().unwrap(),
            e
        );
        exit(6);
    });
    write!(file, "{}", content).unwrap_or_else(|e| {
        eprintln!(
            "Unable to write the file {}.\n{}",
            hfile.to_str().unwrap(),
            e
        );
        exit(7);
    });
    let mut permissions = file.metadata().unwrap().permissions();
    permissions.set_mode(0o755);
}

/// Create 3 files in `.git/hooks` folder
///
/// 1. Create post-commit hook
/// 2. Create pre-checkout hook
/// 3. Create post-checkout hook
///
/// # Arguments
/// * `compression`: The compression that will automatically be used to save the results folder (no, lz4, zstd, zlib or lzma) after a git commit
pub fn create_hooks(compression: &str) {
    let git_folder = get_hooks_folder();
    let pre_commit_cmd = format!("gbl commit --compression {}", &compression);
    let pre_commit_cmd = pre_commit_cmd.as_str();
    let pre_co_cmd = "gbl pre-co";
    let post_co_cmd = "gbl checkout";
    let v = vec![pre_commit_cmd, pre_co_cmd, post_co_cmd];
    let file_name = vec!["post-commit", "pre-checkout", "post-checkout"];
    for (c_cmd, fname) in v.iter().zip(file_name.iter()) {
        let content = format!(
            "#!/bin/sh \n\
        \n\
        {}
        \n\
        ",
            c_cmd
        );
        create_file(&git_folder, fname, &content);
    }
}