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

// "✓ test name 5ms" — passing test lines
static VITEST_PASS_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?m)^\s+✓[^\n]+\n?").unwrap());
// " stdout | src/foo.test.ts" noise header
static STDOUT_HDR_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(?m)^\s+stdout \|[^\n]+\n?").unwrap());
// " stderr |" header
static STDERR_HDR_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(?m)^\s+stderr \|[^\n]+\n?").unwrap());
// Rerun / watch mode noise
static RERUN_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(?m)^(RERUN|Re-running)[^\n]*\n?").unwrap());
// "Duration  Xs (transform Xs, setup Xs, collect Xs, tests Xs)" — keep only first token
#[allow(dead_code)]
static DURATION_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(?m)^( Duration\s+\d+\.\d+\w+)[^\n]*\n?").unwrap());

pub fn compress_vitest(raw: &str, exit_code: i32) -> String {
    let cleaned = compactor::normalise(raw);
    let s = RERUN_RE.replace_all(&cleaned, "");
    let s = STDOUT_HDR_RE.replace_all(&s, "");
    let s = STDERR_HDR_RE.replace_all(&s, "");

    if exit_code == 0 {
        // Keep: suite PASS/FAIL lines, summary block (Test Files, Tests, Duration)
        let out: Vec<&str> = s
            .lines()
            .filter(|l| {
                let t = l.trim();
                !t.is_empty()
                    && (l.contains("✓") && (l.contains("Test Files") || l.contains("Tests"))
                        || t.starts_with("Test Files")
                        || t.starts_with("Tests")
                        || t.starts_with("Duration")
                        || t.starts_with("Start")
                        || t.starts_with("PASS")
                        || t.starts_with("FAIL")
                        || l.contains("passed")
                        || l.contains("failed"))
            })
            .collect();
        if !out.is_empty() {
            return out.join("\n");
        }
        // Fallback: just the summary lines at the end
        let lines: Vec<&str> = s.lines().collect();
        let tail_start = lines.len().saturating_sub(8);
        return lines[tail_start..].join("\n");
    }

    // Failure: strip passing individual test lines, keep failures + summary
    let s = VITEST_PASS_RE.replace_all(&s, "");
    compactor::collapse_blanks(&s)
}

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

    #[test]
    fn success_strips_passing_lines_keeps_summary() {
        let raw = " ✓ src/foo.test.ts (3)\n   ✓ adds numbers 1ms\n   ✓ subtracts numbers 1ms\n\n Test Files  1 passed (1)\n      Tests  3 passed (3)\n   Duration  142ms\n";
        let out = compress_vitest(raw, 0);
        assert!(!out.contains("✓ adds numbers"), "{out}");
        assert!(
            out.contains("Test Files") || out.contains("Tests") || out.contains("Duration"),
            "{out}"
        );
    }

    #[test]
    fn failure_keeps_failing_test_details() {
        let raw = " ✓ src/foo.test.ts (2)\n   ✓ test one 1ms\n   ✓ test two 1ms\n ✗ src/bar.test.ts (1)\n   × test three\n     AssertionError: expected 1 to be 2\n\n Test Files  1 failed | 1 passed (2)\n      Tests  1 failed | 2 passed (3)\n";
        let out = compress_vitest(raw, 1);
        assert!(!out.contains("✓ test one"), "{out}");
        assert!(
            out.contains("AssertionError") || out.contains("failed"),
            "{out}"
        );
    }

    #[test]
    fn strips_rerun_and_stdout_headers() {
        let raw = "RERUN src/foo.test.ts x3\n stdout | src/foo.test.ts\n some log output\n ✗ failing test\n";
        let out = compress_vitest(raw, 1);
        assert!(!out.contains("RERUN"), "{out}");
        assert!(!out.contains("stdout |"), "{out}");
    }
}
