use std::fs;
use std::path::{Path, PathBuf};
use std::str::FromStr;

fn main() {
    cxx_build::bridges(["src/lib.rs", "src/config.rs", "src/login.rs"])
        .std("c++20")
        .compile("dnf_utils");
    println!("cargo:rerun-if-changed=src/lib.rs");
    println!("cargo:rerun-if-changed=src/config.rs");

    let out_dir = "src/protobuf";
    if PathBuf::from_str(out_dir).unwrap().exists() {
        fs::remove_dir_all(out_dir).expect("清空输出目录出错");
    }
    fs::create_dir_all(out_dir).expect("创建输出目录出错");

    let proto_list = get_filenames("proto")
        .expect("读取Protobuf定义文件列表失败")
        .iter()
        .filter_map(|file| {
            if file.ends_with(".proto") {
                Some(file.clone())
            } else {
                None
            }
        })
        .collect::<Vec<_>>();

    prost_build::Config::new()
        .out_dir(out_dir)
        .compile_protos(&proto_list, &["proto/".to_string()])
        .unwrap();

    //tonic_prost_build::configure()
    //    .out_dir(out_dir)
    //    .compile_protos(&proto_list, &["proto/".to_string()])?;

    let mod_file = format!("{}/mod.rs", out_dir);
    let mod_content = get_filenames(out_dir).expect("无法列出目录内容");
    let mod_content = mod_content
        .iter()
        .map(|file| format!("pub mod {};", file.trim_end_matches(".rs")))
        .collect::<Vec<_>>()
        .join("\n");
    fs::write(&mod_file, mod_content).expect("写出文件失败");

    fs::write(
        format!("{}/README.md", out_dir),
        "# Warning！\n\n[protobuf](../protobuf) 中的文件由构建脚本生成，重新生成时将会**删除**此目录内的**全部文件**\
        ，请不要在此目录内工作，否则可能丢失工作进度！\n\n## 你被警告了！",
    ).unwrap();
}

fn get_filenames(dir: &str) -> Result<Vec<String>, std::io::Error> {
    println!("cargo:rerun-if-changed=proto");
    let entries = fs::read_dir(Path::new(dir))?;
    let filenames: Vec<String> = entries
        .filter_map(|entry| {
            let path = entry.ok()?.path();
            if path.is_file() {
                path.file_name()?.to_str().map(|s| s.to_owned())
            } else {
                None
            }
        })
        .collect();
    Ok(filenames)
}
