use std::env;
use std::fs;
use std::path::Path;
use serde_json::Value;

fn main() {
    println!("cargo:rerun-if-changed=mecha10.json");
    println!("cargo:rerun-if-changed=embedded/");

    // 1. Generate node registry from mecha10.json
    generate_node_registry();

    // 2. Generate embedded asset accessors
    generate_embedded_assets();
}

fn generate_node_registry() {
    let manifest_str = fs::read_to_string("mecha10.json")
        .unwrap_or_else(|_| r#"{"nodes":{"drivers":[],"custom":[]}}"#.to_string());
    let manifest: Value = serde_json::from_str(&manifest_str)
        .expect("Failed to parse mecha10.json");

    let mut code = String::from("// Auto-generated from mecha10.json\n\n");

    // Detect run target from features
    let is_robot = env::var("CARGO_FEATURE_TARGET_ROBOT").is_ok();
    let is_remote = env::var("CARGO_FEATURE_TARGET_REMOTE").is_ok();
    let is_dev = env::var("CARGO_FEATURE_TARGET_DEV").is_ok();

    let run_target = if is_dev {
        "dev"
    } else if is_robot {
        "robot"
    } else if is_remote {
        "remote"
    } else {
        "dev"
    };

    code.push_str(&format!("pub const RUN_TARGET: &str = \"{}\";\n\n", run_target));

    // Generate enabled nodes list
    code.push_str("pub const ENABLED_NODES: &[&str] = &[\n");

    if let Some(drivers) = manifest["nodes"]["drivers"].as_array() {
        for driver in drivers {
            if driver["enabled"].as_bool().unwrap_or(false) {
                let name = driver["name"].as_str().unwrap();
                code.push_str(&format!("    \"{}\",\n", name));
            }
        }
    }

    if let Some(custom) = manifest["nodes"]["custom"].as_array() {
        for node in custom {
            if node["enabled"].as_bool().unwrap_or(false) {
                let name = node["name"].as_str().unwrap();
                code.push_str(&format!("    \"{}\",\n", name));
            }
        }
    }

    code.push_str("];\n\n");

    // Generate node dispatcher function
    code.push_str("pub async fn run_node(name: &str) -> anyhow::Result<()> {\n");
    code.push_str("    use mecha10_core::prelude::*;\n\n");
    code.push_str("    match name {\n");

    // Generate match arms for each enabled node
    if let Some(drivers) = manifest["nodes"]["drivers"].as_array() {
        for driver in drivers {
            if driver["enabled"].as_bool().unwrap_or(false) {
                let name = driver["name"].as_str().unwrap();
                let path = driver["path"].as_str().unwrap_or("");

                // Check if this is a monorepo node (path starts with "mecha10-nodes-")
                if path.starts_with("mecha10-nodes-") {
                    let module_name = path.replace('-', "_");
                    code.push_str(&format!(
                        "        \"{}\" => {}::run().await.map_err(|e| anyhow::anyhow!(e)),\n",
                        name, module_name
                    ));
                }
            }
        }
    }

    if let Some(custom) = manifest["nodes"]["custom"].as_array() {
        for node in custom {
            if node["enabled"].as_bool().unwrap_or(false) {
                let name = node["name"].as_str().unwrap();
                let path = node["path"].as_str().unwrap_or("");

                // Check if this is a monorepo node (path starts with "mecha10-nodes-")
                if path.starts_with("mecha10-nodes-") {
                    let module_name = path.replace('-', "_");
                    code.push_str(&format!(
                        "        \"{}\" => {}::run().await.map_err(|e| anyhow::anyhow!(e)),\n",
                        name, module_name
                    ));
                }
            }
        }
    }

    code.push_str("        _ => Err(anyhow::anyhow!(\"Unknown node: {}\", name)),\n");
    code.push_str("    }\n");
    code.push_str("}\n");

    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("node_registry.rs");
    fs::write(&dest_path, code).expect("Failed to write node_registry.rs");
}

fn generate_embedded_assets() {
    let mut code = String::from("// Auto-generated embedded assets\n\n");
    code.push_str("pub struct Embedded;\n\n");
    code.push_str("impl Embedded {\n");

    // Config accessor
    code.push_str("    pub fn config(_path: &str) -> Option<&'static str> {\n");
    code.push_str("        None // TODO: Add configs to embedded/configs/\n");
    code.push_str("    }\n\n");

    // Model accessor
    code.push_str("    pub fn model(_name: &str) -> Option<&'static [u8]> {\n");
    code.push_str("        None // TODO: Add models to embedded/models/\n");
    code.push_str("    }\n\n");

    // List configs
    code.push_str("    pub fn list_configs() -> &'static [&'static str] {\n");
    code.push_str("        &[]\n");
    code.push_str("    }\n\n");

    // List models
    code.push_str("    pub fn list_models() -> &'static [&'static str] {\n");
    code.push_str("        &[]\n");
    code.push_str("    }\n");

    code.push_str("}\n");

    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("embedded.rs");
    fs::write(&dest_path, code).expect("Failed to write embedded.rs");
}
