use forge::signal::compactor;
use once_cell::sync::Lazy;
use regex::Regex;

// Download/fetch chatter and ASCII progress bars Homebrew prints during install.
static FETCH_RE: Lazy<Regex> = Lazy::new(|| {
    Regex::new(
        r"(?m)^\s*(==> (Downloading|Fetching|Pouring|Verifying|Running `brew cleanup)|Already downloaded:|#+\s+\d+\.\d+%)[^\n]*\n?",
    )
    .unwrap()
});

/// brew install/upgrade: drop download + pour + cleanup noise, keep the
/// "==> Installing" steps, the 🍺 summary, and any Warning/Error lines.
pub fn compress_install(raw: &str) -> String {
    let cleaned = compactor::normalise(raw);
    let s = FETCH_RE.replace_all(&cleaned, "");
    compactor::collapse_blanks(&s)
}

/// brew list / search: keep the head of long listings.
pub fn compress_list(raw: &str) -> String {
    let cleaned = compactor::normalise(raw);
    let lines: Vec<&str> = cleaned.lines().collect();
    if lines.len() <= 30 {
        return cleaned;
    }
    format!(
        "{}\n... [{} more formulae] ...",
        lines[..30].join("\n"),
        lines.len() - 30
    )
}

pub fn compress_brew(subcmd: &str, raw: &str) -> String {
    let sub = subcmd.trim();
    if sub.starts_with("install")
        || sub.starts_with("upgrade")
        || sub.starts_with("reinstall")
        || sub.starts_with("uninstall")
        || sub.starts_with("tap")
        || sub.starts_with("bundle")
    {
        return compress_install(raw);
    }
    if sub.starts_with("list") || sub.starts_with("search") || sub.starts_with("outdated") {
        return compress_list(raw);
    }
    compactor::normalise(raw)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn install_strips_download_and_progress() {
        let raw = "==> Downloading https://example.com/foo-1.2.3.bottle.tar.gz\n######################################################################## 100.0%\n==> Installing foo\n==> Pouring foo--1.2.3.arm64.bottle.tar.gz\n🍺  /opt/homebrew/Cellar/foo/1.2.3: 123 files, 4.5MB\n==> Running `brew cleanup foo`...\n";
        let out = compress_install(raw);
        assert!(!out.contains("Downloading"), "{out}");
        assert!(!out.contains("100.0%"), "{out}");
        assert!(!out.contains("Pouring"), "{out}");
        assert!(out.contains("==> Installing foo"), "{out}");
        assert!(out.contains("🍺"), "{out}");
    }

    #[test]
    fn list_truncates_long_output() {
        let raw = (0..50)
            .map(|i| format!("formula{i}"))
            .collect::<Vec<_>>()
            .join("\n");
        let out = compress_list(&raw);
        assert!(out.contains("more formulae"), "{out}");
    }
}
