use roto_codegen::google::protobuf::descriptor::FileDescriptorSet;
use std::fs;
use std::process::Command;

#[test]
fn test_types_generated_code_builds() {
    // 1. Load FileDescriptorSet from data/test_types.desc
    let desc_path = "data/test_types.desc";
    let data = fs::read(desc_path).expect("Failed to read test_types.desc");
    let set = FileDescriptorSet::new(&data)
        .expect("Failed to create FileDescriptorSet from test_types.desc");

    let generated_files = roto_codegen::generator::generate_rust_code(&set, None, false);
    assert!(
        !generated_files.is_empty(),
        "Generated code should not be empty"
    );

    // 2. Setup a temporary Cargo project to verify the code builds
    let root = std::env::current_dir().expect("Failed to get current directory");
    let temp_project_dir = root.join("test_types_gen_project");

    // Clean up previous runs
    if temp_project_dir.exists() {
        fs::remove_dir_all(&temp_project_dir).expect("Failed to clean up temp project directory");
    }

    // Create new library project
    let status = Command::new("cargo")
        .args(["new", "--lib", "test_types_gen_project"])
        .current_dir(&root)
        .status()
        .expect("Failed to run cargo new");
    assert!(status.success(), "cargo new failed");

    // 3. Configure the project to depend on the current roto crate
    let cargo_toml_path = temp_project_dir.join("Cargo.toml");
    let cargo_toml_content =
        fs::read_to_string(&cargo_toml_path).expect("Failed to read Cargo.toml");
    let updated_cargo_toml = format!(
        "{}\n\nroto-codegen = {{ path = \"..\" }}\nroto-runtime = {{ path = \"../../runtime\" }}\n\n[workspace]\n",
        cargo_toml_content
    );
    fs::write(cargo_toml_path, updated_cargo_toml).expect("Failed to write Cargo.toml");

    // 4. Write the generated code to src/lib.rs
    let mut all_code = String::new();
    for (_, content) in generated_files {
        all_code.push_str(&content);
        all_code.push_str("\n");
    }
    // The generated code uses `use crate::{...}`, but it's now in a separate crate.
    // Replace `crate` with `roto` to reference the types in the dependency.
    // Note: in build_generated_code.rs it does replace("use crate::", "use roto::").
    // But here the generated code might not have dependencies since it's a single file.
    // However, to be safe and consistent with the template:
    let final_code = all_code.replace("use crate::", "use roto::");
    let lib_path = temp_project_dir.join("src/lib.rs");
    fs::write(lib_path, final_code).expect("Failed to write generated code to src/lib.rs");

    // 5. Attempt to build the project
    let build_status = Command::new("cargo")
        .args(["--offline", "build"])
        .current_dir(&temp_project_dir)
        .status()
        .expect("Failed to run cargo build");

    assert!(
        build_status.success(),
        "The generated Rust code for test_types.proto failed to build in a standalone project!"
    );
}
