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

// Docker layer cache lines: "#1 CACHED" / "#3 [internal] load build context"
static DOCKER_LAYER_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(?m)^#\d+\s+(?:CACHED|DONE \d|[^\n]*load[^\n]*)\n?").unwrap());
// "[skaffold] watching for changes..." watcher heartbeat
static WATCH_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(?m)^\[skaffold\] watching for changes[^\n]*\n?").unwrap());
// Digest/sha lines in push output
static DIGEST_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(?m)^\s*digest: sha256:[a-f0-9]+\s*\n?").unwrap());

// ── skaffold build ────────────────────────────────────────────────────────────

pub fn compress_build(raw: &str) -> String {
    let cleaned = compactor::normalise(raw);
    let s = DOCKER_LAYER_RE.replace_all(&cleaned, "");
    let s = DIGEST_RE.replace_all(&s, "");
    let useful: Vec<&str> = s
        .lines()
        .filter(|l| {
            let t = l.trim();
            !t.is_empty()
                && (t.contains("Building")
                    || t.contains("built")
                    || t.contains("pushed")
                    || t.contains("tagged")
                    || t.contains("Successfully")
                    || t.contains("ERROR")
                    || t.contains("error")
                    || t.contains("WARN"))
        })
        .collect();
    if useful.is_empty() {
        return compactor::collapse_blanks(&s);
    }
    useful.join("\n")
}

// ── skaffold deploy ───────────────────────────────────────────────────────────

pub fn compress_deploy(raw: &str) -> String {
    let cleaned = compactor::normalise(raw);
    let useful: Vec<&str> = cleaned
        .lines()
        .filter(|l| {
            let t = l.trim();
            !t.is_empty()
                && (t.contains("Deploying")
                    || t.contains("deployed")
                    || t.contains("service")
                    || t.contains("deployment")
                    || t.contains("pod")
                    || t.contains("ready")
                    || t.contains("Running")
                    || t.contains("URL")
                    || t.contains("port")
                    || t.contains("ERROR")
                    || t.contains("error")
                    || t.contains("FAILED"))
        })
        .collect();
    if useful.is_empty() {
        return compactor::collapse_blanks(&cleaned);
    }
    useful.join("\n")
}

// ── skaffold dev (streaming — keep errors + pod events only) ──────────────────

pub fn compress_dev(raw: &str) -> String {
    let cleaned = compactor::normalise(raw);
    let s = WATCH_RE.replace_all(&cleaned, "");
    let s = DOCKER_LAYER_RE.replace_all(&s, "");
    let useful: Vec<&str> = s
        .lines()
        .filter(|l| {
            let t = l.trim();
            !t.is_empty()
                && (t.contains("ERROR")
                    || t.contains("error")
                    || t.contains("WARN")
                    || t.contains("pod")
                    || t.contains("service")
                    || t.contains("ready")
                    || t.contains("port-forwarding")
                    || t.contains("URL"))
        })
        .collect();
    if useful.is_empty() {
        return compactor::collapse_blanks(&s);
    }
    useful.join("\n")
}

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

pub fn compress_skaffold(subcmd: &str, raw: &str) -> String {
    let sub = subcmd.trim();
    if sub.starts_with("build") {
        return compress_build(raw);
    }
    if sub.starts_with("deploy") || sub.starts_with("run") {
        return compress_deploy(raw);
    }
    if sub.starts_with("dev") {
        return compress_dev(raw);
    }
    // delete / diagnose / config — passthrough with noise removed
    let cleaned = compactor::normalise(raw);
    let s = DOCKER_LAYER_RE.replace_all(&cleaned, "");
    compactor::collapse_blanks(&s)
}

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

    #[test]
    fn build_strips_docker_layers() {
        let raw = "#1 [internal] load build definition from Dockerfile\n#1 CACHED\n#2 [internal] load .dockerignore\n#2 CACHED\nBuilding [my-app]...\nSuccessfully built abc123\n";
        let out = compress_build(raw);
        assert!(!out.contains("#1 CACHED"), "{out}");
        assert!(!out.contains("#2 CACHED"), "{out}");
        assert!(
            out.contains("Successfully built") || out.contains("Building"),
            "{out}"
        );
    }

    #[test]
    fn deploy_keeps_service_and_pod_lines() {
        let raw = "kubectl --context kind-kind apply -f /tmp/manifest.yaml\ndeployment.apps/my-app configured\nservice/my-svc unchanged\nWaiting for deployments to stabilize...\nDeployment my-app is ready.\n";
        let out = compress_deploy(raw);
        assert!(
            out.contains("deployment") || out.contains("service") || out.contains("ready"),
            "{out}"
        );
    }

    #[test]
    fn dev_strips_watch_heartbeats() {
        let raw = "[skaffold] watching for changes...\n[skaffold] watching for changes...\npod/my-app-abc ready\n";
        let out = compress_dev(raw);
        assert!(!out.contains("watching for changes"), "{out}");
        assert!(out.contains("ready"), "{out}");
    }
}
