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

static PROGRESS_RE: Lazy<Regex> = Lazy::new(||
    // pnpm progress: "Packages: +12" style or "Progress: resolved 123, reused 456, downloaded 78"
    Regex::new(r"(?m)^(Progress: |Packages: [+\-]|\s+[⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏])[^\n]*\n?").unwrap());
static LOCKFILE_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(?m)^(Lockfile is up to date|Already up to date)[^\n]*\n?").unwrap());
static PEER_WARN_RE: Lazy<Regex> = Lazy::new(||
    // pnpm peer dependency warnings can be verbose
    Regex::new(r"(?m)^\s+(WARN|warn)\s+[^\n]+peer[^\n]*\n?").unwrap());

pub fn compress_install(raw: &str) -> String {
    let cleaned = compactor::normalise(raw);
    let s = PROGRESS_RE.replace_all(&cleaned, "");
    let s = LOCKFILE_RE.replace_all(&s, "");
    // Keep summary lines: "packages installed", "Done in", added/removed counts
    let out: Vec<&str> = s
        .lines()
        .filter(|l| {
            let t = l.trim();
            t.is_empty()
                || t.contains("packages")
                || t.contains("Done in")
                || t.starts_with("ERR")
                || t.contains("error")
                || t.contains("WARN")
        })
        .collect();
    let result = compactor::collapse_blanks(&out.join("\n"));
    if result.trim().is_empty() {
        compactor::collapse_blanks(&s)
    } else {
        result
    }
}

pub fn compress_add(raw: &str) -> String {
    let cleaned = compactor::normalise(raw);
    let s = PROGRESS_RE.replace_all(&cleaned, "");
    let s = PEER_WARN_RE.replace_all(&s, "");
    compactor::collapse_blanks(&s)
}

pub fn compress_pnpm(subcmd: &str, raw: &str) -> String {
    let sub = subcmd.trim();
    match sub {
        "install" | "i" | "update" | "up" => compress_install(raw),
        "add" | "remove" | "rm" => compress_add(raw),
        "run" | "exec" | "dlx" => {
            // Script output: strip pnpm header noise
            let cleaned = compactor::normalise(raw);
            cleaned
                .lines()
                .filter(|l| !l.starts_with("> ") || !l.contains("@"))
                .collect::<Vec<_>>()
                .join("\n")
        }
        _ => compactor::normalise(raw),
    }
}

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

    #[test]
    fn install_strips_progress() {
        let raw = "Progress: resolved 123, reused 45, downloaded 12, added 12, done\n\npackages installed\n";
        let out = compress_install(raw);
        assert!(!out.contains("Progress:"), "{out}");
        assert!(out.contains("packages installed"), "{out}");
    }

    #[test]
    fn install_strips_lockfile_up_to_date() {
        let raw = "Lockfile is up to date, resolution step is skipped\nDone in 1.2s\n";
        let out = compress_install(raw);
        assert!(!out.contains("Lockfile is up to date"), "{out}");
    }
}
