use std::fs;
use std::path::Path;

use super::verify_inside_clippy_dir;

const VSCODE_DIR: &str = ".vscode";
const TASK_SOURCE_FILE: &str = "util/etc/vscode-tasks.json";
const TASK_TARGET_FILE: &str = ".vscode/tasks.json";

pub fn install_tasks(force_override: bool) {
    if !check_install_precondition(force_override) {
        return;
    }

    match fs::copy(TASK_SOURCE_FILE, TASK_TARGET_FILE) {
        Ok(_) => {
            println!("info: the task file can be removed with `cargo dev remove vscode-tasks`");
            println!("vscode tasks successfully installed");
        },
        Err(err) => eprintln!("error: unable to copy `{TASK_SOURCE_FILE}` to `{TASK_TARGET_FILE}` ({err})"),
    }
}

fn check_install_precondition(force_override: bool) -> bool {
    if !verify_inside_clippy_dir() {
        return false;
    }

    let vs_dir_path = Path::new(VSCODE_DIR);
    if vs_dir_path.exists() {
        // verify the target will be valid
        if !vs_dir_path.is_dir() {
            eprintln!("error: the `.vscode` path exists but seems to be a file");
            return false;
        }

        // make sure that we don't override any existing tasks by accident
        let path = Path::new(TASK_TARGET_FILE);
        if path.exists() {
            if force_override {
                return delete_vs_task_file(path);
            }

            eprintln!("error: there is already a `task.json` file inside the `{VSCODE_DIR}` directory");
            println!("info: use the `--force-override` flag to override the existing `task.json` file");
            return false;
        }
    } else {
        match fs::create_dir(vs_dir_path) {
            Ok(_) => {
                println!("info: created `{VSCODE_DIR}` directory for clippy");
            },
            Err(err) => {
                eprintln!("error: the task target directory `{VSCODE_DIR}` could not be created ({err})");
            },
        }
    }

    true
}

pub fn remove_tasks() {
    let path = Path::new(TASK_TARGET_FILE);
    if path.exists() {
        if delete_vs_task_file(path) {
            try_delete_vs_directory_if_empty();
            println!("vscode tasks successfully removed");
        }
    } else {
        println!("no vscode tasks were found");
    }
}

fn delete_vs_task_file(path: &Path) -> bool {
    if let Err(err) = fs::remove_file(path) {
        eprintln!("error: unable to delete the existing `tasks.json` file ({err})");
        return false;
    }

    true
}

/// This function will try to delete the `.vscode` directory if it's empty.
/// It may fail silently.
fn try_delete_vs_directory_if_empty() {
    let path = Path::new(VSCODE_DIR);
    if path.read_dir().map_or(false, |mut iter| iter.next().is_none()) {
        // The directory is empty. We just try to delete it but allow a silence
        // fail as an empty `.vscode` directory is still valid
        let _silence_result = fs::remove_dir(path);
    } else {
        // The directory is not empty or could not be read. Either way don't take
        // any further actions
    }
}
