use super::{AwarenessMap, EcosystemAwareness};
use once_cell::sync::Lazy;
use regex::Regex;

static STATS_RE: Lazy<Regex> = Lazy::new(|| {
    Regex::new(r"(\d+) files? changed(?:, (\d+) insertions?\(\+\))?(?:, (\d+) deletions?\(-\))?")
        .unwrap()
});
static BRANCH_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"On branch (.+)").unwrap());
static AHEAD_BEHIND_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"Your branch is (ahead|behind).+by (\d+) commit").unwrap());
static COMMIT_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"^([0-9a-f]{7,40})\s+(.+)$").unwrap());

pub struct GitAwareness;

impl EcosystemAwareness for GitAwareness {
    fn matches(&self, program: &str, _args: &[String]) -> bool {
        matches!(
            program.split('/').next_back().unwrap_or(program),
            "git" | "gh" | "jj"
        )
    }

    fn extract(&self, stdout: &str, stderr: &str, exit_code: i32) -> AwarenessMap {
        let mut map = AwarenessMap::new("vcs", "git");
        map.insert("exit_code", exit_code.to_string());

        let combined = format!("{stdout}\n{stderr}");

        if let Some(cap) = BRANCH_RE.captures(&combined) {
            map.insert("branch", cap[1].trim().to_string());
        }
        if let Some(cap) = STATS_RE.captures(&combined) {
            map.insert("files_changed", cap[1].to_string());
            if let Some(ins) = cap.get(2) {
                map.insert("insertions", ins.as_str().to_string());
            }
            if let Some(del) = cap.get(3) {
                map.insert("deletions", del.as_str().to_string());
            }
        }
        if let Some(cap) = AHEAD_BEHIND_RE.captures(&combined) {
            map.insert("ahead_behind", cap[1].to_string());
            map.insert("ahead_behind_count", cap[2].to_string());
        }

        let commit_count = COMMIT_RE.captures_iter(stdout).count();
        if commit_count > 0 {
            map.insert("commit_count", commit_count.to_string());
        }

        map
    }
}
