use std::os::unix::fs::PermissionsExt;
use std::path::Path;

const INVALID_CHARS: [&str; 19] = [
    "@", "\\", "/", ":", ",", "<", ">", "%", "'", "\"", "?", "{", "}", "$", "*", "|", ";", "=",
    "\t",
];

/// Check out whether a file name is valid or not
pub fn check_file_name(name: &str) -> bool {
    !name.is_empty() && !INVALID_CHARS.iter().any(|c| name.contains(c))
}

/// Create directory if missing
pub fn create_directory_if_missing<P: AsRef<Path>>(path: P) -> anyhow::Result<()> {
    let path = path.as_ref();
    if !path.exists() {
        std::fs::create_dir_all(path)?;
    }
    Ok(())
}

/// Update file permission
pub fn set_file_permission<P: AsRef<Path>>(path: P, mode: u32) -> anyhow::Result<()> {
    let mut perms = std::fs::metadata(path.as_ref())?.permissions();
    perms.set_mode(mode);
    std::fs::set_permissions(path.as_ref(), perms)?;
    Ok(())
}

#[cfg(test)]
mod test {
    use crate::utils::files_utils::check_file_name;

    #[test]
    fn empty_file_name() {
        assert!(!check_file_name(""));
    }

    #[test]
    fn parent_dir_file_name() {
        assert!(!check_file_name("../file.test"));
    }

    #[test]
    fn windows_parent_dir_file_name() {
        assert!(!check_file_name("..\\test.fr"));
    }

    #[test]
    fn special_char_file_name() {
        assert!(!check_file_name("test:test.@"));
    }

    #[test]
    fn valid_file_name() {
        assert!(check_file_name("test.iso"));
    }
}