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

// Strip connection noise and verbose metadata
static CONN_NOISE_RE: Lazy<Regex> = Lazy::new(|| {
    Regex::new(r"(?m)^(mysql: \[Warning\]|Welcome to the MySQL|Your MySQL connection id|Server version:)[^\n]*\n?").unwrap()
});
#[allow(dead_code)]
static EMPTY_SET_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(?m)^Empty set \(\d+\.\d+ sec\)\n?").unwrap());
static ROWS_RE: Lazy<Regex> = Lazy::new(||
    // "3 rows in set (0.00 sec)" — keep but normalise
    Regex::new(r"(?m)^\d+ rows? in set \(\d+\.\d+ sec\)").unwrap());

pub fn compress_mysql(raw: &str) -> String {
    let cleaned = compactor::normalise(raw);
    let s = CONN_NOISE_RE.replace_all(&cleaned, "");
    // Truncate large result sets (> 50 rows)
    let lines: Vec<&str> = s.lines().collect();
    if lines.len() > 55 {
        // Keep header (first 2 lines = border + header) + 50 data rows + row count
        let row_count_line = lines.iter().rfind(|l| ROWS_RE.is_match(l));
        let head = &lines[..2.min(lines.len())];
        let body = &lines[2..52.min(lines.len())];
        let omitted = lines.len().saturating_sub(52);
        let mut out = head.join("\n");
        out.push('\n');
        out.push_str(&body.join("\n"));
        out.push_str(&format!("\n... [{} more rows omitted] ...", omitted));
        if let Some(rc) = row_count_line {
            out.push('\n');
            out.push_str(rc);
        }
        return out;
    }
    compactor::collapse_blanks(&s)
}

pub fn compress_mysqldump(raw: &str) -> String {
    let cleaned = compactor::normalise(raw);
    // Strip verbose comment blocks (-- Server version, -- Host, etc.)
    let kept: Vec<&str> = cleaned
        .lines()
        .filter(|l| {
            let t = l.trim();
            !(t.starts_with("-- Server version")
                || t.starts_with("-- Host:")
                || t.starts_with("-- Dump completed")
                || t.starts_with("-- MySQL dump")
                || t.starts_with("/*!"))
        })
        .collect();
    kept.join("\n")
}

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

    #[test]
    fn strips_connection_warnings() {
        let raw = "mysql: [Warning] Using a password on the command line interface can be insecure.\nid | name\n1  | foo\n1 row in set (0.00 sec)\n";
        let out = compress_mysql(raw);
        assert!(!out.contains("[Warning]"), "{out}");
        assert!(out.contains("foo"), "{out}");
    }

    #[test]
    fn truncates_large_result_set() {
        let header = "+----+--------+\n| id | name   |\n+----+--------+\n";
        let rows: String = (0..60)
            .map(|i| format!("| {i:2} | name{i:2} |\n"))
            .collect();
        let footer = "+----+--------+\n60 rows in set (0.01 sec)\n";
        let raw = format!("{header}{rows}{footer}");
        let out = compress_mysql(&raw);
        assert!(out.contains("omitted"), "{out}");
    }
}
