//! Build script: stage a clean copy of the repo `render/` package into `OUT_DIR`
//! so `src/embedded.rs` can `include_dir!` it without tripping over the dev-only
//! self-referential symlink at `render/vendor/local-packages/`.
//!
//! Why this exists: `include_dir!` walks a directory at compile time and follows
//! symlinks. The repo keeps `render/vendor/local-packages/local/cph-render/0.1.0`
//! as a symlink pointing back at `render/` (a gitignored dev convenience for
//! typst's local-package resolution). Embedding `render/` directly would make
//! `include_dir!` recurse into that link forever. The runtime never needs that
//! link (the engine resolves `@local/cph-render` from the render dir directly,
//! and `@preview/*` from `vendor/typst-packages/`), so we copy everything EXCEPT
//! `vendor/local-packages/` into `OUT_DIR/render` and embed that staged tree.

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

fn main() {
    let manifest_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
    let render_src = manifest_dir.join("..").join("..").join("render");
    let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
    let staged = out_dir.join("render");

    // Rebuild the staged tree from scratch each run (cheap — ~140 KiB).
    if staged.exists() {
        let _ = std::fs::remove_dir_all(&staged);
    }
    copy_tree(&render_src, &staged).expect("stage render/ for embedding");

    // Re-run when the render package changes.
    println!("cargo:rerun-if-changed={}", render_src.display());
    // Expose the staged path to the crate via an env var include_dir! can read.
    println!("cargo:rustc-env=CPH_STAGED_RENDER_DIR={}", staged.display());
}

/// Recursively copy `src` → `dst`, skipping the dev-only `vendor/local-packages`
/// subtree and never following symlinks into it.
fn copy_tree(src: &Path, dst: &Path) -> std::io::Result<()> {
    std::fs::create_dir_all(dst)?;
    for entry in std::fs::read_dir(src)? {
        let entry = entry?;
        let name = entry.file_name();
        let from = entry.path();
        let to = dst.join(&name);

        // Skip the self-referential dev symlink tree.
        if from.ends_with("vendor/local-packages") || name == *"local-packages" {
            continue;
        }

        // Resolve symlinks/metadata without following into a cycle: use
        // `symlink_metadata` so a symlinked dir is treated by its link, not its
        // (recursive) target. We only copy real files and real directories.
        let meta = std::fs::symlink_metadata(&from)?;
        let ft = meta.file_type();
        if ft.is_symlink() {
            // Skip any symlink (the only one in the tree is the dev convenience).
            continue;
        } else if ft.is_dir() {
            copy_tree(&from, &to)?;
        } else if ft.is_file() {
            std::fs::copy(&from, &to)?;
        }
    }
    Ok(())
}
