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

static COMPILE_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(?m)^Compile Swift Module '[^']+' \(\d+ sources?\)\n?").unwrap());
static LINK_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?m)^Linking \S+\n?").unwrap());
static FETCH_PROGRESS_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(?m)^(Fetching|Cloning|Resolving) [^\n]+\n?").unwrap());

pub fn compress_build(raw: &str, exit_code: i32) -> String {
    let cleaned = compactor::normalise(raw);
    let s = COMPILE_RE.replace_all(&cleaned, "");
    let s = LINK_RE.replace_all(&s, "");
    if exit_code == 0 {
        return compactor::collapse_blanks(&s);
    }
    // Keep error/warning lines
    let kept: Vec<&str> = s
        .lines()
        .filter(|l| l.contains("error:") || l.contains("warning:") || !l.trim().is_empty())
        .collect();
    if kept.len() < 5 {
        return compactor::collapse_blanks(&s);
    }
    // Too many lines — filter to errors/warnings only
    s.lines()
        .filter(|l| l.contains("error:") || l.contains("warning:"))
        .collect::<Vec<_>>()
        .join("\n")
}

pub fn compress_test(raw: &str, exit_code: i32) -> String {
    let cleaned = compactor::normalise(raw);
    let s = COMPILE_RE.replace_all(&cleaned, "");
    if exit_code == 0 {
        // Keep "Test Suite passed" / "Executed N tests"
        let kept: Vec<&str> = s
            .lines()
            .filter(|l| {
                l.contains("Test Suite")
                    || l.contains("Executed")
                    || l.contains("passed")
                    || l.contains("failed")
            })
            .collect();
        if !kept.is_empty() {
            return kept.join("\n");
        }
    }
    // Failure: keep all (usually short) or filter to failures
    compactor::collapse_blanks(&s)
}

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

pub fn compress_swift(subcmd: &str, raw: &str, exit_code: i32) -> String {
    let sub = subcmd.trim();
    match sub {
        "build" | "run" => compress_build(raw, exit_code),
        "test" => compress_test(raw, exit_code),
        "package" | "resolve" => compress_package_resolve(raw),
        _ => compactor::normalise(raw),
    }
}

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

    #[test]
    fn build_strips_compile_lines() {
        let raw = "Compile Swift Module 'MyLib' (3 sources)\nLinking MyLib\nBuild complete!\n";
        let out = compress_build(raw, 0);
        assert!(!out.contains("Compile Swift Module"), "{out}");
        assert!(!out.contains("Linking MyLib"), "{out}");
        assert!(out.contains("Build complete"), "{out}");
    }

    #[test]
    fn test_success_keeps_summary() {
        let raw = "Compile Swift Module 'MyTests' (2 sources)\nTest Suite 'AllTests' passed\nExecuted 5 tests, with 0 failures\n";
        let out = compress_test(raw, 0);
        assert!(out.contains("passed"), "{out}");
    }
}
