use std::{
    env,
    io::{self, Write},
    path::{Path, PathBuf},
    process,
};

fn main() {
    println!("cargo::rustc-check-cfg=cfg(web_sys_unstable_apis)");
    println!("cargo:rerun-if-changed=uno.config.ts");
    println!("cargo:rerun-if-changed=package.json");
    println!("cargo:rerun-if-changed=tailwind.config.js");

    // Routes are embedded by the shared crate's build process

    // Skip CSS build in development mode if SKIP_CSS_BUILD is set or if package.json not found
    if env::var("SKIP_CSS_BUILD").is_ok() {
        println!("cargo:warning=Skipping CSS build due to SKIP_CSS_BUILD environment variable");
        return;
    }

    // Check if we're in a framework-only context (no package.json available)
    let package_json_paths = ["../package.json", "package.json", "../../package.json", "../../../package.json", "../../../../package.json"];
    let has_package_json = package_json_paths
        .iter()
        .any(|path| Path::new(path).exists());

    if !has_package_json {
        println!("cargo:warning=No package.json found - assuming framework-only build, skipping CSS processing");
        return;
    }

    // Check if node_modules exists in various locations, if not run pnpm install
    let node_modules_paths = ["../node_modules", "node_modules", "../../node_modules"];

    let node_modules_exists = node_modules_paths
        .iter()
        .any(|path| Path::new(path).exists());

    if !node_modules_exists {
        println!("cargo:warning=node_modules not found, running pnpm install...");

        // Try to find package.json to determine correct directory
        let package_json_paths = ["../package.json", "package.json", "../../package.json", "../../../package.json", "../../../../package.json"];

        let install_dir = package_json_paths
            .iter()
            .find(|path| Path::new(path).exists())
            .map(|path| Path::new(path).parent().unwrap_or(Path::new(".")))
            .unwrap_or(Path::new(".."));

        match process::Command::new("pnpm")
            .arg("install")
            .current_dir(install_dir)
            .output()
        {
            Ok(output) => {
                if !output.status.success() {
                    let _ = io::stdout().write_all(&output.stdout);
                    let _ = io::stdout().write_all(&output.stderr);
                    panic!("pnpm install failed");
                }
                println!("cargo:warning=pnpm install completed successfully");
            }
            Err(e) => {
                println!("cargo:warning=Failed to run pnpm install: {e:?}");
                println!("cargo:warning=Please run 'pnpm install' manually in the project root");
                // Don't panic here, just warn - the build might still work
            }
        }
    }

    // Use build coordinator for CSS build to prevent duplication
    let css_output_path = PathBuf::from("public/website.css");
    let css_sources = vec![
        PathBuf::from("uno.config.ts"),
        PathBuf::from("package.json"),
        PathBuf::from("tailwind.config.js"),
    ];

    // Try to use the build coordinator, fall back to direct build if it fails
    match coordinate_css_build(&css_output_path, &css_sources) {
        Ok(built) => {
            if built {
                println!("cargo:warning=CSS build completed successfully via coordinator");
            } else {
                println!("cargo:warning=CSS build skipped - already up to date");
            }
        }
        Err(e) => {
            println!("cargo:warning=Build coordinator failed: {}, falling back to direct build", e);
            run_direct_css_build();
        }
    }
}

/// Coordinate CSS build using the build coordinator from tools crate
fn coordinate_css_build(output_path: &Path, source_paths: &[PathBuf]) -> Result<bool, String> {
    // Since tools crate may not be available during client build, we'll implement
    // a simple coordinator check here instead of importing tools
    use std::fs;

    // Simple freshness check without full coordinator
    if output_path.exists() {
        let output_meta = fs::metadata(output_path).map_err(|e| e.to_string())?;
        let output_modified = output_meta.modified().map_err(|e| e.to_string())?;

        let mut needs_rebuild = false;
        for source_path in source_paths {
            if source_path.exists() {
                let source_meta = fs::metadata(source_path).map_err(|e| e.to_string())?;
                let source_modified = source_meta.modified().map_err(|e| e.to_string())?;

                if source_modified > output_modified {
                    needs_rebuild = true;
                    break;
                }
            }
        }

        if !needs_rebuild {
            return Ok(false); // No rebuild needed
        }
    }

    // Need to build - run the CSS build
    run_direct_css_build();
    Ok(true)
}

/// Run direct CSS build without coordinator
fn run_direct_css_build() {
    match process::Command::new("sh")
        .arg("-c")
        .arg("pnpm run build")
        .output()
    {
        Ok(output) => {
            if !output.status.success() {
                let _ = io::stdout().write_all(&output.stdout);
                let _ = io::stdout().write_all(&output.stderr);
                panic!("UnoCSS error");
            }
        }
        Err(e) => panic!("UnoCSS error: {e:?}"),
    };
}
