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

// non-critical warning lines starting with ‼ (information symbol)
static INFO_WARN_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?m)^‼[^\n]*\n?").unwrap());
// version mismatch noise: "client version: X.Y.Z, server version: X.Y.Z"
static VERSION_MISMATCH_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(?m)^(?:client|server) version:[^\n]*\n?").unwrap());

// ── linkerd check ─────────────────────────────────────────────────────────────

pub fn compress_check(raw: &str) -> String {
    let cleaned = compactor::normalise(raw);
    let s = INFO_WARN_RE.replace_all(&cleaned, "");
    let s = VERSION_MISMATCH_RE.replace_all(&s, "");

    let mut pass_count = 0usize;
    let mut failures: Vec<String> = Vec::new();
    let mut categories: Vec<String> = Vec::new();

    for line in s.lines() {
        let t = line.trim();
        if t.is_empty() {
            continue;
        }
        if t.starts_with('√') || t.starts_with("ok") {
            pass_count += 1;
        } else if t.starts_with('×')
            || t.starts_with("×")
            || t.contains("FAILED")
            || t.contains("error")
        {
            failures.push(t.to_string());
        } else if t.ends_with(':') || (t.len() < 60 && !t.contains(' ')) {
            // Category header line
            categories.push(t.to_string());
        }
    }

    let mut out: Vec<String> = Vec::new();
    if pass_count > 0 {
        out.push(format!("  ✔  {} checks passed", pass_count));
    }
    out.extend(failures);
    if out.is_empty() {
        return compactor::collapse_blanks(&s);
    }
    out.join("\n")
}

// ── linkerd stat ──────────────────────────────────────────────────────────────

pub fn compress_stat(raw: &str) -> String {
    let cleaned = compactor::normalise(raw);
    // Table output — keep header + rows, truncate at 30
    let lines: Vec<&str> = cleaned.lines().filter(|l| !l.trim().is_empty()).collect();
    if lines.len() > 30 {
        return format!(
            "{}\n… [{} more rows]",
            lines[..30].join("\n"),
            lines.len() - 30
        );
    }
    lines.join("\n")
}

// ── linkerd inject ────────────────────────────────────────────────────────────

pub fn compress_inject(raw: &str) -> String {
    // inject outputs YAML — passthrough but collapse blanks
    compactor::collapse_blanks(&compactor::normalise(raw))
}

// ── top-level dispatcher ──────────────────────────────────────────────────────

pub fn compress_linkerd(subcmd: &str, raw: &str) -> String {
    let sub = subcmd.trim();
    if sub.starts_with("check") {
        return compress_check(raw);
    }
    if sub.starts_with("stat") || sub.starts_with("top") {
        return compress_stat(raw);
    }
    if sub.starts_with("inject") {
        return compress_inject(raw);
    }
    // install / upgrade / viz / uninstall
    let cleaned = compactor::normalise(raw);
    let s = INFO_WARN_RE.replace_all(&cleaned, "");
    compactor::collapse_blanks(&s)
}

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

    #[test]
    fn check_summarises_passes_and_shows_failures() {
        let raw = "linkerd-config\n√ control plane Namespace exists\n√ control plane ClusterRoles exist\n√ control plane ClusterRoleBindings exist\n‼ gap in control plane version\nlinkerd-identity\n√ certificate config is valid\n× certificate is expiring soon: cert expires in 3 days\n";
        let out = compress_check(raw);
        assert!(!out.contains('‼'), "{out}");
        assert!(out.contains("passed") || out.contains('√'), "{out}");
        assert!(out.contains("expiring") || out.contains('×'), "{out}");
    }

    #[test]
    fn stat_truncates_long_table() {
        let mut lines = vec![
            "NAME  MESHED  SUCCESS  RPS  LATENCY_P50  LATENCY_P95  LATENCY_P99  TCP_CONN"
                .to_string(),
        ];
        for i in 0..35 {
            lines.push(format!("svc-{i}  1/1  100.00%  1.5rps  1ms  2ms  4ms  3"));
        }
        let out = compress_stat(&lines.join("\n"));
        assert!(out.contains("more rows"), "{out}");
    }
}
