//! Git helpers (plan §11). We shell out to the installed `git` CLI rather than
//! link libgit2 (no cmake/openssl in the build env). Change *detection* for
//! `update` is done by content hash in the manifest, so it works for non-git
//! repos too; git here supplies the commit SHA for provenance and `--commit`.

use anyhow::{Context, Result};
use std::path::Path;
use std::process::Command;

fn git(root: &Path, args: &[&str]) -> Option<String> {
    let out = Command::new("git")
        .arg("-C")
        .arg(root)
        .args(args)
        .output()
        .ok()?;
    if !out.status.success() {
        return None;
    }
    Some(String::from_utf8_lossy(&out.stdout).trim().to_string())
}

/// Current HEAD commit SHA (short), if this is a git repo with commits.
pub fn head_commit(root: &Path) -> Option<String> {
    git(root, &["rev-parse", "--short", "HEAD"])
}

/// Stage the wiki + state dirs and commit. Best-effort; returns the new SHA.
///
/// `wiki_dir` may be relative or absolute; git is finicky about absolute paths
/// from `-C`, so we pass it relative to the repo root when possible.
pub fn commit_wiki(root: &Path, wiki_dir: &str, message: &str) -> Result<Option<String>> {
    let wiki_arg = match Path::new(wiki_dir).strip_prefix(root) {
        Ok(rel) => rel.to_string_lossy().to_string(),
        Err(_) => wiki_dir.to_string(),
    };

    let add = Command::new("git")
        .arg("-C")
        .arg(root)
        .args(["add", "--", &wiki_arg, ".hephaes"])
        .status()
        .context("git add")?;
    if !add.success() {
        return Ok(None); // wiki dir outside the repo, or git unavailable
    }

    let status = Command::new("git")
        .arg("-C")
        .arg(root)
        .args(["commit", "-m", message])
        .status()
        .context("git commit")?;

    if status.success() {
        Ok(head_commit(root))
    } else {
        // Nothing to commit, or commit failed — non-fatal for the run.
        Ok(None)
    }
}
