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

static STEP_RE: Lazy<Regex> = Lazy::new(||
    // "step N/M: zig build-lib foo Debug native"
    Regex::new(r"(?m)^step \d+/\d+: [^\n]+\n?").unwrap());
static FETCH_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?m)^fetch [^\n]+\n?").unwrap());

pub fn compress_build(raw: &str, exit_code: i32) -> String {
    let cleaned = compactor::normalise(raw);
    let s = STEP_RE.replace_all(&cleaned, "");
    let s = FETCH_RE.replace_all(&s, "");
    if exit_code == 0 {
        return compactor::collapse_blanks(&s);
    }
    // Keep error lines: "path/to/file.zig:line:col: error: message"
    s.lines()
        .filter(|l| l.contains("error:") || l.contains("note:") || l.trim().is_empty())
        .collect::<Vec<_>>()
        .join("\n")
}

pub fn compress_test(raw: &str, exit_code: i32) -> String {
    let cleaned = compactor::normalise(raw);
    let s = STEP_RE.replace_all(&cleaned, "");
    if exit_code == 0 {
        // Keep "All N tests passed"
        let kept: Vec<&str> = s
            .lines()
            .filter(|l| l.contains("passed") || l.contains("PASS") || l.contains("tests"))
            .collect();
        if !kept.is_empty() {
            return kept.join("\n");
        }
    }
    // On failure: filter to FAIL lines
    s.lines()
        .filter(|l| l.contains("FAIL") || l.contains("error:") || l.trim().is_empty())
        .collect::<Vec<_>>()
        .join("\n")
}

pub fn compress_zig(subcmd: &str, raw: &str, exit_code: i32) -> String {
    match subcmd.trim() {
        "build" | "build-exe" | "build-lib" | "build-obj" => compress_build(raw, exit_code),
        "test" => compress_test(raw, exit_code),
        _ => compactor::normalise(raw),
    }
}

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

    #[test]
    fn build_strips_step_lines() {
        let raw = "step 1/4: zig build-lib foo Debug native\nstep 2/4: zig build-lib bar Debug native\nstep 3/4: zig build-exe main Debug native\nstep 4/4: install\n";
        let out = compress_build(raw, 0);
        assert!(!out.contains("step 1/4:"), "{out}");
    }

    #[test]
    fn build_failure_keeps_errors() {
        let raw =
            "step 1/3: zig build-lib foo Debug native\nsrc/main.zig:10:5: error: expected ';'\n";
        let out = compress_build(raw, 1);
        assert!(out.contains("error:"), "{out}");
        assert!(!out.contains("step 1/3:"), "{out}");
    }

    #[test]
    fn test_success_keeps_summary() {
        let raw = "step 1/2: zig test\nAll 12 tests passed.\n";
        let out = compress_test(raw, 0);
        assert!(out.contains("passed"), "{out}");
        assert!(!out.contains("step 1/2"), "{out}");
    }
}
