use std::{
    env, fs,
    path::{Path, PathBuf},
};

pub mod codegen;
pub mod manifest;
pub mod native_build;
pub mod orchestrator;

pub use codegen::{
    MsgCodeGen, NodeCodeGen, NodePort, NodeSpec, OpaqueCodeGen, OpaqueField, PortDirection,
};
pub use manifest::{ManifestEntry, MsgManifest, NodeManifest, OpaqueManifest};
pub use native_build::{NativeBackend, NativeBuildConfig, NativePackage};
pub use orchestrator::{BuildContext, BuildOrchestrator};
/// 构建辅助结构体，封装了 CMake 和 CXX 的构建逻辑
pub struct BuildHelper {
    cpp_source: String,
    cpp_lib_name: String,
    bridge_file: String,
    bridge_name: String,
    cmake_generator: Option<String>,
}

impl Default for BuildHelper {
    fn default() -> Self {
        Self {
            cpp_source: "cpp".into(),
            cpp_lib_name: "node_lib".into(),
            bridge_file: "src/lib.rs".into(),
            bridge_name: "cxx_bridge".into(),
            cmake_generator: None,
        }
    }
}

impl BuildHelper {
    /// 设置 C++ 源码目录 (相对于 crate 根目录)
    pub fn cpp_source(mut self, dir: &str) -> Self {
        self.cpp_source = dir.into();
        self
    }

    /// 设置 CMake 生成的静态库名称 (不含 lib 前缀和后缀)
    pub fn cpp_lib_name(mut self, name: &str) -> Self {
        self.cpp_lib_name = name.into();
        self
    }

    /// 设置包含 `#[cxx::bridge]` 的 Rust 文件路径
    pub fn bridge_file(mut self, file: &str) -> Self {
        self.bridge_file = file.into();
        self
    }

    /// 设置编译生成的 bridge 库名称
    pub fn bridge_name(mut self, name: &str) -> Self {
        self.bridge_name = name.into();
        self
    }

    /// 手动指定 CMake Generator (例如 "Visual Studio 17 2022")
    pub fn cmake_generator(mut self, generator: &str) -> Self {
        self.cmake_generator = Some(generator.into());
        self
    }

    /// 执行构建流程
    pub fn build(self) {
        let manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("NotInCargoProject");
        let manifest_path = PathBuf::from(&manifest_dir);

        // 1. 环境准备：获取依赖路径
        let roplat_include = Self::get_roplat_include();
        let cxx_bridge_include = Self::get_cxx_bridge_include(&manifest_path);

        // 2. 环境配置：Generator
        self.configure_generator();

        // 3. 构建 C++ 库 (CMake)
        let dst = self.build_cmake(&manifest_path, &roplat_include, &cxx_bridge_include);

        // 4. 链接配置
        println!("cargo:rustc-link-search=native={}/lib", dst.display());
        println!("cargo:rustc-link-lib=static={}", self.cpp_lib_name);

        // 5. 编译 CXX Bridge
        self.build_cxx_bridge(&manifest_path, &roplat_include);
    }

    /// 获取 roplat-cpp 的头文件路径
    pub fn get_roplat_include() -> PathBuf {
        env::var("DEP_ROPLAT_CPP_INCLUDE")
            .map(PathBuf::from)
            .unwrap_or_else(|_| {
                // 打印调试信息以帮助排查
                for (key, value) in env::vars() {
                    if key.starts_with("DEP_") {
                        println!("cargo:warning=Found env: {}={}", key, value);
                    }
                }
                panic!("Failed to get DEP_ROPLAT_CPP_INCLUDE. Ensure roplat_cpp is a dependency.");
            })
    }

    /// 获取 cxx 生成的头文件路径 (处理 Workspace 结构)
    pub fn get_cxx_bridge_include(manifest_dir: &Path) -> PathBuf {
        // 在 Workspace 中，target 目录通常在根目录
        // 简单的向上查找策略
        let workspace_root = manifest_dir
            .parent()
            .expect("Cannot find workspace root (parent of manifest_dir)");

        workspace_root.join("target/cxxbridge")
    }

    /// 配置 CMake Generator
    pub fn configure_generator(&self) {
        // 如果用户在 BuildHelper 中显式指定了 generator，且环境变量中没有设置，则应用它
        if let Some(gene) = &self.cmake_generator
            && env::var("CMAKE_GENERATOR").is_err()
            && cfg!(target_os = "windows")
        {
            println!("cargo:warning=Forcing CMAKE_GENERATOR to '{}'", gene);
            unsafe {
                env::set_var("CMAKE_GENERATOR", gene);
            }
        }
    }

    /// 运行 CMake 构建
    fn build_cmake(
        &self,
        manifest_dir: &Path,
        roplat_include: &Path,
        cxx_bridge_include: &Path,
    ) -> PathBuf {
        let dst = cmake::Config::new(&self.cpp_source)
            // 注入源码头文件路径
            .cxxflag(format!("-I{}", roplat_include.display()))
            // 注入 cxx 生成的头文件路径
            .cxxflag(format!("-I{}", cxx_bridge_include.display()))
            // 强制生成 compile_commands.json
            .define("CMAKE_EXPORT_COMPILE_COMMANDS", "ON")
            .build();

        // 将 compile_commands.json 复制到 crate 根目录，方便 IDE 使用
        let build_dir = dst.join("build");
        let source_json = build_dir.join("compile_commands.json");
        let dest_json = manifest_dir.join("compile_commands.json");

        if source_json.exists() {
            let _ = fs::copy(&source_json, &dest_json);
            println!("cargo:warning=Updated compile_commands.json for VS Code C++ IntelliSense");
        } else {
            println!(
                "cargo:warning=Could not find compile_commands.json in {:?}",
                build_dir
            );
        }

        dst
    }

    /// 编译 Rust-C++ Bridge
    fn build_cxx_bridge(&self, manifest_dir: &Path, roplat_include: &Path) {
        cxx_build::bridge(&self.bridge_file)
            .include(roplat_include)
            .include(manifest_dir)
            .compile(&self.bridge_name);
    }
}
