use std::path::Path;
use std::process::Command;

use crate::error::{SouthError, SouthResult};

fn run_git(args: &[&str]) -> SouthResult<()> {
    let output = Command::new("git")
        .args(args)
        .output()
        .map_err(|e| SouthError::GitError(format!("Failed to execute git: {}", e)))?;

    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        return Err(SouthError::GitError(format!(
            "git {} failed: {}",
            args.join(" "),
            stderr.trim()
        )));
    }

    Ok(())
}

/// Clone a repository to the given destination path.
pub fn git_clone(url: &str, dest: &Path) -> SouthResult<()> {
    run_git(&["clone", url, &dest.to_string_lossy()])
}

/// Clone a repository and checkout a specific revision.
pub fn git_clone_at_revision(url: &str, dest: &Path, revision: &str) -> SouthResult<()> {
    git_clone(url, dest)?;
    git_checkout(dest, revision)
}

/// Fetch and checkout a specific revision in an existing repository.
pub fn git_checkout(repo_path: &Path, revision: &str) -> SouthResult<()> {
    let repo = repo_path.to_string_lossy();
    run_git(&["-C", &repo, "fetch", "origin"])?;
    run_git(&["-C", &repo, "checkout", revision])
}

/// Check if a directory is a valid git repository.
pub fn is_git_repo(path: &Path) -> bool {
    path.join(".git").exists()
}
