use std::env;
use std::error::Error;
use std::path::{Path, PathBuf};

fn main() -> Result<(), Box<dyn Error>> {
    configure_protoc();

    let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?);

    // Resolve the proto source directory. In-repo builds prefer the canonical
    // Contracts protos (two levels above clients/rust) so local `.proto` edits
    // are picked up live. When that path is absent — e.g. a consumer building
    // the crate unpacked from a published tarball — fall back to the vendored
    // copies shipped in `clients/rust/protos/` (see build.rs staleness note and
    // CLI-02 in archreview/remediation/50-clients.md). Vendored copies are
    // build inputs only; the canonical source remains in Contracts and must be
    // refreshed here whenever the `.proto` files change.
    let repo_proto_root = manifest_dir
        .parent()
        .and_then(Path::parent)
        .map(|repo_root| repo_root.join("src/ZB.MOM.WW.MxGateway.Contracts/Protos"));
    let vendored_proto_root = manifest_dir.join("protos");
    let proto_root = match repo_proto_root {
        Some(path) if path.is_dir() => path,
        _ => vendored_proto_root,
    };

    let gateway_proto = proto_root.join("mxaccess_gateway.proto");
    let worker_proto = proto_root.join("mxaccess_worker.proto");
    let galaxy_proto = proto_root.join("galaxy_repository.proto");
    let descriptor_path = PathBuf::from(env::var("OUT_DIR")?).join("mxaccessgw-client-v1.protoset");

    println!("cargo:rerun-if-changed={}", gateway_proto.display());
    println!("cargo:rerun-if-changed={}", worker_proto.display());
    println!("cargo:rerun-if-changed={}", galaxy_proto.display());

    tonic_build::configure()
        .build_server(true)
        .build_client(true)
        .file_descriptor_set_path(descriptor_path)
        .compile_protos(
            &[
                gateway_proto.as_path(),
                worker_proto.as_path(),
                galaxy_proto.as_path(),
            ],
            &[proto_root.as_path()],
        )?;

    Ok(())
}

fn configure_protoc() {
    if env::var_os("PROTOC").is_some() {
        return;
    }

    for candidate in protoc_candidates() {
        if candidate.is_file() {
            env::set_var("PROTOC", candidate);
            return;
        }
    }
}

fn protoc_candidates() -> Vec<PathBuf> {
    let mut candidates = Vec::new();

    if cfg!(windows) {
        if let Some(local_app_data) = env::var_os("LOCALAPPDATA") {
            candidates.push(PathBuf::from(local_app_data).join(
                "Microsoft/WinGet/Packages/Google.Protobuf_Microsoft.Winget.Source_8wekyb3d8bbwe/bin/protoc.exe",
            ));
        }
    }

    candidates.push(PathBuf::from("protoc"));
    candidates
}
