pub fn compress(cmd: &str, output: &str) -> Option<String> {
    let trimmed = output.trim();
    if trimmed.is_empty() {
        return Some("ok".to_string());
    }

    if cmd.contains("test") {
        return Some(compress_test(trimmed));
    }
    if cmd.contains("install") || cmd.contains("add") || cmd.contains("remove") {
        return Some(compress_install(trimmed));
    }
    if cmd.contains("build") || cmd.contains("run") {
        return Some(compress_build(trimmed));
    }

    Some(compact_lines(trimmed, 15))
}

fn compress_test(output: &str) -> String {
    let mut passed = 0u32;
    let mut failed = 0u32;
    let mut skipped = 0u32;
    let mut failures = Vec::new();
    let mut time = String::new();

    for line in output.lines() {
        let trimmed = line.trim();
        let plain = strip_ansi(trimmed);
        if plain.contains("pass") && (plain.contains("tests") || plain.contains("test")) {
            for word in plain.split_whitespace() {
                if let Ok(n) = word.parse::<u32>() {
                    passed = n;
                    break;
                }
            }
        }
        if plain.contains("fail") && !plain.starts_with("FAIL") {
            for word in plain.split_whitespace() {
                if let Ok(n) = word.parse::<u32>() {
                    failed = n;
                    break;
                }
            }
        }
        if plain.contains("skip") {
            for word in plain.split_whitespace() {
                if let Ok(n) = word.parse::<u32>() {
                    skipped = n;
                    break;
                }
            }
        }
        if plain.starts_with("FAIL") || plain.starts_with("✗") || plain.starts_with("×") {
            failures.push(plain.clone());
        }
        if (plain.contains("Ran") || plain.contains("Done"))
            && (plain.contains("ms") || plain.contains("s"))
        {
            time = plain.clone();
        }
    }

    if passed == 0 && failed == 0 {
        return compact_lines(output, 10);
    }

    let mut result = format!("bun test: {passed} passed");
    if failed > 0 {
        result.push_str(&format!(", {failed} failed"));
    }
    if skipped > 0 {
        result.push_str(&format!(", {skipped} skipped"));
    }
    if !time.is_empty() {
        result.push_str(&format!(" ({time})"));
    }
    for f in failures.iter().take(5) {
        result.push_str(&format!("\n  {f}"));
    }
    result
}

fn compress_install(output: &str) -> String {
    let mut installed = 0u32;
    let mut removed = 0u32;
    let mut time = String::new();

    for line in output.lines() {
        let plain = strip_ansi(line.trim());
        if plain.contains("installed") || plain.starts_with('+') {
            installed += 1;
        }
        if plain.contains("removed") || plain.starts_with('-') {
            removed += 1;
        }
        if plain.contains("done") && (plain.contains("ms") || plain.contains("s")) {
            time = plain.clone();
        }
    }

    let mut parts = Vec::new();
    if installed > 0 {
        parts.push(format!("{installed} installed"));
    }
    if removed > 0 {
        parts.push(format!("{removed} removed"));
    }
    if !time.is_empty() {
        parts.push(time);
    }

    if parts.is_empty() {
        return compact_lines(output, 5);
    }
    format!("bun: {}", parts.join(", "))
}

fn compress_build(output: &str) -> String {
    let lines: Vec<&str> = output.lines().collect();
    let errors: Vec<&&str> = lines
        .iter()
        .filter(|l| l.contains("error") || l.contains("Error"))
        .collect();
    if !errors.is_empty() {
        let mut result = format!("{} errors:", errors.len());
        for e in errors.iter().take(10) {
            result.push_str(&format!("\n  {}", e.trim()));
        }
        return result;
    }
    compact_lines(output, 10)
}

fn strip_ansi(s: &str) -> String {
    crate::core::compressor::strip_ansi(s)
}

fn compact_lines(text: &str, max: usize) -> String {
    let lines: Vec<&str> = text.lines().filter(|l| !l.trim().is_empty()).collect();
    if lines.len() <= max {
        return lines.join("\n");
    }
    format!(
        "{}\n... ({} more lines)",
        lines[..max].join("\n"),
        lines.len() - max
    )
}
