use std::fs;
use std::io::Write;

use uuid::Uuid;
use cs_trace::FileWriter;

#[test]
#[should_panic]
fn panics_if_invalid_file_path() {
    let _ = FileWriter::new("");
}

#[test]
fn creates_folder_and_file_if_not_present() {
    let (logs_folder, _, _) = create_log_writer(Uuid::new_v4().to_string());

    remove_folder(logs_folder);
}

#[test]
fn appends_logs_to_the_file() {
    let (logs_folder, file_path, mut file_writer) = create_log_writer(Uuid::new_v4().to_string());

    let _ = file_writer.write("hello\n".as_bytes());
    let _ = file_writer.flush();

    let _ = file_writer.write("test\n".as_bytes());
    let _ = file_writer.flush();

    let _ = file_writer.write("world!\n".as_bytes());
    let _ = file_writer.flush();

    let contents = get_file_contents(file_path);

    remove_folder(logs_folder);

    assert_eq!(contents.lines().count(), 3);
}

// - Helpers

#[cfg(test)]
fn get_file_contents<T: AsRef<str> + ToString>(file_path: T) -> String {
    let file_path = file_path.as_ref();

    let contents = fs::read_to_string(file_path)
        .expect(
            &format!("Cannot read file contents at [{}].", file_path),
        );

    return contents;
}

#[cfg(test)]
fn create_log_writer<'a>(folder_name: String) -> (String, String, Box<dyn Write>) {
    let file_folder = format!("/tmp/utils/{}", folder_name);
    let file_name = format!("{}/logs.log", file_folder);

    let file_writer = FileWriter::new(&file_name);

    return (file_folder, file_name, file_writer);
}

#[cfg(test)]
fn remove_folder<T: AsRef<str> + ToString>(file_folder: T) -> () {
    let file_folder = file_folder.as_ref();

    let _ = fs::remove_dir_all(&file_folder)
        .expect(
            &format!("Cannot remove folder at [{}].", &file_folder)
        );
}