#![cfg(feature = "_build")]
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

fn get_protos_recursively(root: &Path) -> std::io::Result<Vec<PathBuf>> {
    let mut protos = Vec::new();
    for entry in fs::read_dir(root)? {
        let entry = entry?;
        if entry.path().is_dir() {
            protos.append(&mut get_protos_recursively(&entry.path())?)
        } else if let Some(ext) = entry.path().extension() {
            if ext == "proto" {
                protos.push(entry.path())
            }
        }
    }
    Ok(protos)
}

fn main() {
    let manifest_dir =
        env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR environment variable not set");
    let manifest_path = Path::new(&manifest_dir);

    let out_dir: PathBuf = env::var("PROTO_OUT_DIR")
        .map(PathBuf::from)
        .unwrap_or_else(|_| manifest_path.join("src/proto"));

    let proto_mod_file = out_dir.join("mod.rs");
    fs::create_dir_all(&out_dir).expect("Failed to create proto output directory");

    if let Ok(descriptor_set_path) = env::var("PROTO_DESCRIPTOR_SET") {
        // Bazel path: use pre-compiled descriptor set
        let descriptor_bytes =
            fs::read(&descriptor_set_path).expect("Failed to read proto descriptor set");
        let fds = <prost_types::FileDescriptorSet as prost::Message>::decode(
            descriptor_bytes.as_slice(),
        )
        .expect("Failed to decode proto descriptor set");

        tonic_build::configure()
            .build_server(false)
            .emit_rerun_if_changed(false)
            .compile_well_known_types(true)
            .include_file(&proto_mod_file)
            .out_dir(&out_dir)
            .compile_fds(fds)
            .expect("Failed to compile tonic gRPC stubs from descriptor set");
    } else {
        // Cargo path: use raw .proto files from definitions/
        let proto_input = manifest_path.join("definitions/protos/");
        let proto_files = get_protos_recursively(&proto_input).unwrap_or_else(|_| {
            panic!(
                "compile-protos: {} not found; this is a bug with nominal-api-proto",
                proto_input.display()
            )
        });

        tonic_build::configure()
            .build_server(false)
            .emit_rerun_if_changed(false)
            .compile_well_known_types(true)
            .include_file(&proto_mod_file)
            .out_dir(&out_dir)
            .compile_protos(
                &proto_files,
                &[
                    proto_input.clone(),
                    manifest_path.join("definitions/proto-includes/"),
                ],
            )
            .expect("Failed to compile tonic gRPC stubs from proto definitions");
    }

    // `gen` is a reserved keyword in Rust 2024
    let content =
        fs::read_to_string(&proto_mod_file).expect("Failed to read generated tonic.rs file");
    let modified_content = content.replace("pub mod gen", "pub mod r#gen");
    fs::write(&proto_mod_file, modified_content).expect("Failed to write modified tonic.rs file");
}
