use crate::config::Config;
use anyhow::{Context, Result};
use std::path::Path;

pub fn run_git(config: &Config, args: &[String]) -> Result<()> {
    let cmd = build_git_command(config, args);
    run_in_dir(&cmd, &config.storage_dir)
}

pub fn run_autogit(config: &Config) -> Result<()> {
    let cmd = format!(
        "git add . && git commit -m \"$(date)\" && git pull {} {} && git push {} {}",
        config.git_remote, config.git_branch, config.git_remote, config.git_branch,
    );
    run_in_dir(&cmd, &config.storage_dir)
}

pub fn run_cmd(config: &Config, args: &[String]) -> Result<()> {
    let cmd = args.join(" ");
    run_in_dir(&cmd, &config.storage_dir)
}

fn build_git_command(config: &Config, args: &[String]) -> String {
    match args.first().map(|s| s.as_str()) {
        Some("auto") => format!(
            "git add . && git commit -m \"$(date)\" && git pull {} {} && git push {} {}",
            config.git_remote, config.git_branch, config.git_remote, config.git_branch,
        ),
        Some("autocommit") => "git add . && git commit -m \"$(date)\"".into(),
        Some(_) => format!("git {}", shell_join(args)),
        None => "git status".into(),
    }
}

fn shell_join(args: &[String]) -> String {
    args.iter()
        .map(|a| {
            if a.contains(' ') {
                format!("\"{}\"", a)
            } else {
                a.clone()
            }
        })
        .collect::<Vec<_>>()
        .join(" ")
}

fn run_in_dir(cmd: &str, dir: &Path) -> Result<()> {
    std::process::Command::new("sh")
        .arg("-c")
        .arg(cmd)
        .current_dir(dir)
        .status()
        .with_context(|| format!("failed to run: {}", cmd))?;
    Ok(())
}
