use log::warn;
use std::io::Result;
use tokio::fs;

pub async fn walk_dir(dir: &str) -> Vec<String> {
    let mut todo = Vec::new();
    if let Ok(rd) = read_dir(dir).await {
        todo.push(rd);
    }

    let mut results = Vec::new();

    while let Some(rd) = todo.pop() {
        for (path, is_dir) in rd {
            if is_dir {
                let Ok(child_rd) = (read_dir(&path).await)
                    .inspect_err(|e| warn!("reading dir {path} failed: {e}"))
                else {
                    continue;
                };
                todo.push(child_rd);
            } else {
                results.push(path);
            }
        }
    }

    results
}

async fn read_dir(dir: &str) -> Result<Vec<(String, bool)>> {
    let mut rd = fs::read_dir(dir).await?;
    let mut entries = Vec::new();

    while let Some(entry) = rd.next_entry().await? {
        if let Some(path) = entry.path().to_str() {
            entries.push((path.to_string(), entry.file_type().await?.is_dir()));
        }
    }

    entries.sort(); // we want a deterministic & intuitive order
    Ok(entries)
}
