#[cfg(test)]
mod tests_repository {
    use crate::domain;
    use crate::domain::media;
    use crate::repository::json::JsonRepository;
    use crate::repository::Error;
    use crate::repository::Repository;
    use std::collections::{HashMap, VecDeque};
    use std::fs;
    use std::string::String;
    use std::vec::Vec;

    #[test]
    fn test_save_a_user() -> Result<(), Error> {
        let file = format!("{}/test_save_a_user.json", DIRECTORY);
        let _ = fs::remove_file(file.clone());
        let mut repo = JsonRepository::new(&file)?;
        let name = String::from("foo");
        let medias: HashMap<String, media::Media> = [
            (
                String::from("bar"),
                media::Media {
                    name: String::from("bar"),
                    chapters: Vec::new(),
                    cursor: media::Cursor::default(),
                    source: Some(String::from("alpha")),
                },
            ),
            (
                String::from("too"),
                media::Media {
                    name: String::from("too"),
                    chapters: Vec::new(),
                    cursor: media::Cursor::default(),
                    source: None,
                },
            ),
        ]
        .iter()
        .cloned()
        .collect();
        let user = domain::User::new(name.clone(), medias);

        match repo.save(&user) {
            Err(e) => panic!("{:?}", e),
            Ok(_) => assert_eq!(repo.users()[&(name.clone())], user),
        };
        Ok(())
    }

    #[test]
    fn test_load_a_user() -> Result<(), Error> {
        let file = format!("{}/test_load_a_user.json", DIRECTORY);
        let _ = fs::remove_file(file.clone());
        let mut repo = JsonRepository::new(&file)?;
        let name = String::from("foo");
        let user = domain::User::new(name.clone(), HashMap::new());
        match repo.save(&user) {
            Ok(_) => match repo.load(&name) {
                Ok(resp) => assert_eq!(resp, user),
                Err(e) => panic!("{:?}", e),
            },
            Err(e) => panic!("{:?}", e),
        }

        Ok(())
    }

    #[test]
    fn test_load_multiple_users() -> Result<(), Error> {
        let file = format!("{}/test_load_multiple_users.json", DIRECTORY);
        let _ = fs::remove_file(file.clone());
        let mut repo = JsonRepository::new(&file)?;

        let users = vec![
            domain::User::new(String::from("foo"), HashMap::new()),
            domain::User::new(String::from("bar"), HashMap::new()),
            domain::User::new(String::from("too"), HashMap::new()),
        ];

        for user in users.iter() {
            if let Err(e) = repo.save(user) {
                panic!("{:?}", e)
            }
        }

        for user in users.iter() {
            match repo.load(user.name()) {
                Ok(u) => assert_eq!(u, *user),
                Err(e) => panic!("{:?}", e),
            }
        }
        Ok(())
    }

    #[test]
    fn test_persistance() -> Result<(), Error> {
        let file = format!("{}/test_persistance.json", DIRECTORY);
        let _ = fs::remove_file(file.clone());
        let mut repo = JsonRepository::new(&file.clone())?;

        let users = vec![
            domain::User::new(String::from("foo"), HashMap::new()),
            domain::User::new(String::from("bar"), HashMap::new()),
            domain::User::new(String::from("too"), HashMap::new()),
        ];

        for user in users.iter() {
            if let Err(e) = repo.save(user) {
                panic!("{:?}", e)
            }
        }

        let new_repo = JsonRepository::new(&file.clone())?;
        for user in users.iter() {
            match new_repo.load(user.name()) {
                Ok(u) => assert_eq!(u, *user),
                Err(e) => panic!("{:?}", e),
            }
        }

        Ok(())
    }

    #[test]
    fn test_update_a_user() -> Result<(), Error> {
        let file = format!("{}/test_update_a_user.json", DIRECTORY);
        let _ = fs::remove_file(file.clone());
        let mut repo = JsonRepository::new(&file)?;
        let name = String::from("foo");
        let user = domain::User::new(name.clone(), HashMap::new());
        let medias: HashMap<String, media::Media> = [
            (
                String::from("bar"),
                media::Media {
                    name: String::from("bar"),
                    chapters: Vec::new(),
                    cursor: media::Cursor::default(),
                    source: None,
                },
            ),
            (
                String::from("too"),
                media::Media {
                    name: String::from("too"),
                    chapters: Vec::new(),
                    cursor: media::Cursor {
                        current: None,
                        history: VecDeque::new(),
                    },
                    source: None,
                },
            ),
        ]
        .iter()
        .cloned()
        .collect();

        let _ = repo.save(&user).expect("unable to save");
        let mut user_modified = user.clone();
        user_modified.medias = medias;
        user_modified.name = String::from("bar");

        match repo.update(&user.name, &user_modified) {
            Ok(_) => match repo.load(&user_modified.name) {
                Ok(u) => assert_eq!(u, user_modified),
                Err(e) => panic!("{:?}", e),
            },
            Err(e) => panic!("{:?}", e),
        }
        Ok(())
    }

    #[test]
    fn test_update_a_non_existant_user() -> Result<(), Error> {
        let file = format!("{}/test_update_a_non_existant_user.json", DIRECTORY);
        let _ = fs::remove_file(file.clone());
        let mut repo = JsonRepository::new(&file)?;
        let name = String::from("foo");
        let user = domain::User::new(name.clone(), HashMap::new());

        let _ = repo.save(&user).expect("unable to save");

        let mut user_modified = user.clone();
        user_modified.name = String::from("bar");

        match repo.update(&String::from("do not exist"), &user_modified) {
            Ok(_) => panic!("should not have been able to update"),
            Err(_) => return Ok(()),
        }
    }

    #[test]
    fn test_delete_a_user_with_one_user() -> Result<(), Error> {
        let file = format!("{}/test_delete_a_user_with_one_user.json", DIRECTORY);
        let _ = fs::remove_file(file.clone());
        let mut repo = JsonRepository::new(&file)?;
        let name = String::from("foo");
        let user = domain::User::new(name.clone(), HashMap::new());

        let _ = repo.save(&user).expect("unable to save");
        let _ = repo.delete(&user.name).expect("unable to delete a user");

        match repo.size() {
            Ok(size) => {
                assert_eq!(size, 0);
                Ok(())
            }
            Err(e) => panic!("{:?}", e),
        }
    }

    #[test]
    fn test_delete_a_user_with_multiple_user() -> Result<(), Error> {
        let file = format!("{}/test_delete_a_user_with_only_one_user.json", DIRECTORY);
        let _ = fs::remove_file(file.clone());
        let mut repo = JsonRepository::new(&file)?;
        let user_to_delete = String::from("to delete");
        let users = vec![
            domain::User::new(user_to_delete.clone(), HashMap::new()),
            domain::User::new(String::from("bar"), HashMap::new()),
            domain::User::new(String::from("too"), HashMap::new()),
            domain::User::new(String::from("zoo"), HashMap::new()),
        ];

        for user in users.iter() {
            let _ = repo.save(&user).expect("unable to save");
        }

        let _ = repo
            .delete(&user_to_delete)
            .expect("unable to delete a user");

        match repo.size() {
            Ok(size) => {
                assert_eq!(size, users.len() - 1);
                Ok(())
            }
            Err(e) => panic!("{:?}", e),
        }
    }

    #[test]
    fn test_clear_repository_with_users() -> Result<(), Error> {
        let file = format!("{}/test_clear_repository_with_users.json", DIRECTORY);
        let _ = fs::remove_file(file.clone());
        let mut repo = JsonRepository::new(&file)?;
        let user_to_delete = String::from("to delete");
        let users = vec![
            domain::User::new(user_to_delete.clone(), HashMap::new()),
            domain::User::new(String::from("bar"), HashMap::new()),
            domain::User::new(String::from("too"), HashMap::new()),
            domain::User::new(String::from("zoo"), HashMap::new()),
        ];

        for user in users.iter() {
            let _ = repo.save(&user).expect("unable to save");
        }

        match repo.clear() {
            Err(e) => panic!("{:?}", e),
            Ok(_) => match repo.size() {
                Ok(size) => {
                    assert_eq!(size, 0);
                    Ok(())
                }
                Err(e) => panic!("{:?}", e),
            },
        }
    }
    #[test]
    fn test_clear_empty_repository() -> Result<(), Error> {
        let file = format!("{}/test_clear_empty_repository.json", DIRECTORY);
        let _ = fs::remove_file(file.clone());
        let mut repo = JsonRepository::new(&file)?;

        match repo.clear() {
            Err(e) => panic!("{:?}", e),
            Ok(_) => match repo.size() {
                Ok(size) => {
                    assert_eq!(size, 0);
                    Ok(())
                }
                Err(e) => panic!("{:?}", e),
            },
        }
    }

    const DIRECTORY: &str = "./src/repository/test_files";
}
