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

// "INFO  [alembic.runtime.migration] ..." log prefix
static INFO_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(?m)^INFO\s+\[alembic\.[^\]]+\]\s+").unwrap());

// ── alembic upgrade / downgrade ───────────────────────────────────────────────

pub fn compress_migrate(raw: &str) -> String {
    let cleaned = compactor::normalise(raw);
    // Strip INFO prefix, keep the message content
    let s = INFO_RE.replace_all(&cleaned, "");
    let useful: Vec<&str> = s
        .lines()
        .filter(|l| {
            let t = l.trim();
            !t.is_empty()
                && (t.contains("Running upgrade")
                    || t.contains("Running downgrade")
                    || t.contains("->")
                    || t.contains("<-")
                    || t.contains("Done")
                    || t.contains("error")
                    || t.contains("Error"))
        })
        .collect();
    if useful.is_empty() {
        return compactor::collapse_blanks(&s);
    }
    useful.join("\n")
}

// ── alembic current ───────────────────────────────────────────────────────────

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

// ── alembic history ───────────────────────────────────────────────────────────

pub fn compress_history(raw: &str) -> String {
    let cleaned = compactor::normalise(raw);
    let s = INFO_RE.replace_all(&cleaned, "");
    let lines: Vec<&str> = s.lines().filter(|l| !l.trim().is_empty()).collect();
    if lines.len() > 20 {
        return format!(
            "{}\n… [{} more revisions]",
            lines[..20].join("\n"),
            lines.len() - 20
        );
    }
    lines.join("\n")
}

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

pub fn compress_alembic(subcmd: &str, raw: &str) -> String {
    let sub = subcmd.trim();
    if sub.starts_with("upgrade") || sub.starts_with("downgrade") {
        return compress_migrate(raw);
    }
    if sub.starts_with("current") {
        return compress_current(raw);
    }
    if sub.starts_with("history") {
        return compress_history(raw);
    }
    // revision / stamp / merge
    let cleaned = compactor::normalise(raw);
    let s = INFO_RE.replace_all(&cleaned, "");
    compactor::collapse_blanks(&s)
}

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

    #[test]
    fn upgrade_strips_info_prefix() {
        let raw = "INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.\nINFO  [alembic.runtime.migration] Will assume transactional DDL.\nINFO  [alembic.runtime.migration] Running upgrade  -> abc123, add users table\nINFO  [alembic.runtime.migration] Running upgrade abc123 -> def456, add orders table\n";
        let out = compress_alembic("upgrade head", raw);
        assert!(!out.contains("INFO  [alembic"), "{out}");
        assert!(
            out.contains("add users table") || out.contains("->"),
            "{out}"
        );
    }

    #[test]
    fn history_truncates() {
        let lines: Vec<String> = (0..25)
            .map(|i| format!("rev{i:03} -> rev{:03}, migration {i}", i + 1))
            .collect();
        let out = compress_history(&lines.join("\n"));
        assert!(out.contains("more revisions"), "{out}");
    }
}
