// build script: regenerate chapters.rs
#![allow(clippy::style, clippy::complexity, clippy::perf)]

use std::{
    env, fs,
    io::Write as _,
    path::{Path, PathBuf},
};

const WARNING: &str = "\
// This file is automatically generated by build.rs.
//
// Do not edit by hand.
";

fn modname(p: &Path) -> String {
    let m = p.file_stem().unwrap().to_str().unwrap();
    m.to_ascii_lowercase().replace("-", "_")
}

/// Return a list of the md files linked from `inp`, relative to location of `inp`.
///
/// Assumes that `inp` has the structure of a SUMMARY.md file, and so
/// ignores everything but `[]()` links.
fn find_md_files(inp: &Path) -> anyhow::Result<Vec<PathBuf>> {
    // I would prefer to use `pulldown-cmark` here, but it doesn't
    // work with our MSRV. :P
    let re = regex::Regex::new(r"\]\((.*\.md)\)")?;
    let contents = fs::read_to_string(inp)?;

    Ok(re
        .captures_iter(&contents)
        .map(|c| PathBuf::from(c.get(1).unwrap().as_str()))
        .collect())
}

fn main() -> anyhow::Result<()> {
    let tests_dir: PathBuf = env::var("CARGO_MANIFEST_DIR").unwrap().into();
    let out_dir: PathBuf = env::var_os("OUT_DIR").unwrap().into();
    let book_dir = tests_dir.parent().unwrap();
    let book_src_dir = book_dir.join("src");
    let summary_md_path = book_src_dir.join("SUMMARY.md");

    // Find all the .md files.
    let md_files = find_md_files(&summary_md_path)?;

    // Tell cargo to re-run this script if there is a change to:
    //   - the script itself,
    //   - the SUMMARY.md file,
    //   - any of the MD files we found.
    println!("cargo::rerun-if-changed=build.rs");
    println!("cargo::rerun-if-changed={}", summary_md_path.display());
    for fname in md_files.iter() {
        println!(
            "cargo::rerun-if-changed={}",
            book_src_dir.join(fname).display()
        );
    }

    // Regenerate chapters.rs.
    let chapters_path = out_dir.join("book_chapters.rs");

    let mut f = fs::File::create(chapters_path).unwrap();
    writeln!(f, "{}", WARNING)?;

    for fname in md_files {
        writeln!(
            f,
            r#"
#[doc = include_str!(
    concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/../src/{}"
    )
 )]"#,
            fname.display()
        )?;
        writeln!(f, "mod {} {{}}", modname(fname.as_path()))?;
    }

    Ok(())
}
