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

static REFRESH_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(?m)^[^\n]*: Refreshing state\.\.\.[^\n]*\n?").unwrap());
static DOTS_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?m)^\.\.\.\n?").unwrap());
static DOWNLOAD_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(?m)^- (Finding|Installing|Downloading)[^\n]+\n?").unwrap());

// ── terraform plan ────────────────────────────────────────────────────────────

pub fn compress_plan(raw: &str) -> String {
    let cleaned = compactor::normalise(raw);
    // Strip refresh noise
    let s = REFRESH_RE.replace_all(&cleaned, "");
    let s = DOTS_RE.replace_all(&s, "");
    compactor::collapse_blanks(&s)
}

// ── terraform apply ───────────────────────────────────────────────────────────

pub fn compress_apply(raw: &str) -> String {
    let cleaned = compactor::normalise(raw);
    let s = REFRESH_RE.replace_all(&cleaned, "");
    // Strip "Still creating…" / "Still destroying…" progress lines
    let out: Vec<&str> = s
        .lines()
        .filter(|l| {
            !l.contains(": Still ")
                && !l.contains(": Creating...")
                && !l.contains(": Destroying...")
        })
        .collect();
    compactor::collapse_blanks(&out.join("\n"))
}

// ── terraform init ────────────────────────────────────────────────────────────

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

// ── terraform validate / fmt ──────────────────────────────────────────────────

pub fn compress_validate(raw: &str) -> String {
    compactor::normalise(raw)
}

// ── terraform show ────────────────────────────────────────────────────────────

pub fn compress_show(raw: &str) -> String {
    let cleaned = compactor::normalise(raw);
    // Strip "# resource" comment headers from state show, keep attribute lines
    let lines: Vec<&str> = cleaned.lines().collect();
    if lines.len() <= 60 {
        return cleaned;
    }
    format!(
        "{}\n... [{} more lines — full state omitted] ...",
        lines[..60].join("\n"),
        lines.len() - 60
    )
}

// ── terraform output ──────────────────────────────────────────────────────────

pub fn compress_output(raw: &str) -> String {
    // Output is already compact key = value format — normalise only
    compactor::normalise(raw)
}

// ── terraform state ───────────────────────────────────────────────────────────

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

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

pub fn compress_terraform(subcmd: &str, raw: &str) -> String {
    let sub = subcmd.trim();
    if sub.starts_with("plan") {
        return compress_plan(raw);
    }
    if sub.starts_with("apply") {
        return compress_apply(raw);
    }
    if sub.starts_with("destroy") {
        return compress_apply(raw);
    }
    if sub.starts_with("init") {
        return compress_init(raw);
    }
    if sub.starts_with("validate") || sub.starts_with("fmt") {
        return compress_validate(raw);
    }
    if sub.starts_with("show") {
        return compress_show(raw);
    }
    if sub.starts_with("output") {
        return compress_output(raw);
    }
    if sub.starts_with("state") {
        return compress_state(raw);
    }
    if sub.starts_with("workspace") {
        return compress_workspace(raw);
    }
    if sub.starts_with("providers") {
        return compress_providers(raw);
    }
    compactor::normalise(raw)
}

// ── terraform workspace ───────────────────────────────────────────────────────

pub fn compress_workspace(raw: &str) -> String {
    // workspace list/show/new/select are already compact
    compactor::normalise(raw)
}

// ── terraform providers ───────────────────────────────────────────────────────

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

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

    #[test]
    fn plan_strips_refreshing() {
        let raw = "aws_instance.foo: Refreshing state... [id=i-abc]\nPlan: 1 to add, 0 to change, 0 to destroy.\n";
        let out = compress_plan(raw);
        assert!(!out.contains("Refreshing state"), "{out}");
        assert!(out.contains("Plan: 1 to add"));
    }

    #[test]
    fn apply_strips_still_creating() {
        let raw = "aws_instance.foo: Creating...\naws_instance.foo: Still creating... [10s elapsed]\naws_instance.foo: Creation complete\n";
        let out = compress_apply(raw);
        assert!(!out.contains("Still creating"), "{out}");
        assert!(out.contains("Creation complete"));
    }

    #[test]
    fn init_strips_download_lines() {
        let raw = "Initializing the backend...\n- Finding hashicorp/aws versions matching \"~> 4.0\"...\n- Installing hashicorp/aws v4.67.0...\nTerraform has been successfully initialized!\n";
        let out = compress_init(raw);
        assert!(!out.contains("Finding hashicorp"), "{out}");
        assert!(out.contains("successfully initialized"));
    }
}
