Documentation
use std::fs;

use include_dir::{Dir, include_dir};

use crate::MyConfig;
use crate::runner::init::init_git::init_git;
use crate::runner::init::init_template::init_template;

mod init_template;
mod init_git;

static TEMPLATE_DIR: Dir<'_> = include_dir!("src/template");

///执行初始化命令
pub fn runner_init(conf: MyConfig) -> Result<(), String> {
    //获取name参数
    let project_name = conf.name.as_ref().unwrap();
    //判断name在本地是否有同名文件夹或文件
    if let Ok(_) = fs::metadata(project_name) {
        return Err(format!("name已经存在: {project_name}"));
    }
    //输出文件
    if let Err(e) = init_template(&TEMPLATE_DIR, &conf) {
        return Err(format!("模板文件解析失败: {e}"));
    }
    //初始化git
    if let Err(e) = init_git(&conf) {
        return Err(format!("git初始化失败: {e}"));
    };
    Ok(())
}

#[cfg(test)]
mod tests {
    use std::path::PathBuf;
    use uuid::Uuid;
    use crate::MyCommand;

    use super::*;

    #[cfg(test)]
    #[macro_export]
    macro_rules! assert_contains {
        ($filename:expr, $test_name:expr) => {
            if let Ok(c) = fs::read_to_string($filename) {
                assert!(c.contains($test_name));
            } else {
                assert!(false);
            }
        };
    }

    fn setup(test_name: &str) {
        //检查测试文件夹是否存在,如果存在则先删除
        let result = fs::metadata(&test_name);
        if let Ok(m) = result {
            if m.is_dir() {
                fs::remove_dir_all(&test_name).unwrap();
            } else {
                fs::remove_file(&test_name).unwrap();
            }
        }
    }

    fn teardown(test_name: &str) {
        //删除测试文件夹
        fs::remove_dir_all(test_name).unwrap();
    }

    #[test]
    fn test_runner_init_normal() {
        let test_name = Uuid::new_v4().to_string();
        const TEST_DESC: &str = "我的文档";
        setup(&test_name);
        //初始化参数
        let config = MyConfig {
            command: MyCommand::INIT,
            name: Some(test_name.to_string()),
            title: Some(TEST_DESC.to_string()),
            skip_git: false,
        };
        //执行init命令
        runner_init(config).unwrap();
        //校验是否成功
        assert_contains!(format!("{test_name}/antora.yml"),&test_name);
        assert_contains!(format!("{test_name}/antora-playbook.yml"),&test_name);
        assert_contains!(format!("{test_name}/antora.yml"),TEST_DESC);
        assert_contains!(format!("{test_name}/antora-playbook.yml"),TEST_DESC);
        teardown(&test_name);
    }

    #[test]
    fn test_runner_init_without_desc() {
        let test_name = Uuid::new_v4().to_string();

        setup(&test_name);
        //初始化参数
        let config = MyConfig {
            command: MyCommand::INIT,
            name: Some(test_name.to_string()),
            title: None,
            skip_git: false,
        };
        //执行init命令
        runner_init(config).unwrap();
        //校验是否成功
        assert_contains!(format!("{test_name}/antora.yml"),&test_name);
        assert_contains!(format!("{test_name}/antora-playbook.yml"),&test_name);
        assert_contains!(format!("{test_name}/antora.yml"),&test_name);
        assert_contains!(format!("{test_name}/antora-playbook.yml"),&test_name);
        teardown(&test_name);
    }

    #[test]
    fn test_git_init() {
        let test_name = Uuid::new_v4().to_string();
        setup(&test_name);
        fs::create_dir_all(&test_name).unwrap();
        //初始化参数
        let config = MyConfig {
            command: MyCommand::INIT,
            name: Some(test_name.to_string()),
            title: None,
            skip_git: false,
        };
        init_git(&config).unwrap();
        let git_path = format!("{test_name}/.git");
        assert!(fs::metadata(PathBuf::from(&git_path)).is_ok());
        assert!(fs::metadata(PathBuf::from(format!("{git_path:}/config"))).is_ok());
        assert!(fs::metadata(PathBuf::from(format!("{git_path:}/hooks"))).is_ok());
        teardown(&test_name);
    }

    #[test]
    fn test_skip_git() {
        let test_name = Uuid::new_v4().to_string();
        setup(&test_name);
        fs::create_dir_all(&test_name).unwrap();
        //初始化参数
        let config = MyConfig {
            command: MyCommand::INIT,
            name: Some(test_name.to_string()),
            title: None,
            skip_git: true,
        };
        init_git(&config).unwrap();
        let git_path = format!("{test_name}/.git");
        assert!(fs::metadata(PathBuf::from(&git_path)).is_err());
        assert!(fs::metadata(PathBuf::from(format!("{git_path:}/config"))).is_err());
        assert!(fs::metadata(PathBuf::from(format!("{git_path:}/hooks"))).is_err());
        teardown(&test_name);
    }
}