use std::process::Command;

use anyhow::{anyhow, Result};
use tabby_common::config::{Config, Repository};

trait ConfigExt {
    fn sync_repositories(&self) -> Result<()>;
}

impl ConfigExt for Config {
    fn sync_repositories(&self) -> Result<()> {
        for repository in self.repositories.iter() {
            repository.sync()?;
        }

        Ok(())
    }
}

trait RepositoryExt {
    fn sync(&self) -> Result<()>;
}

impl RepositoryExt for Repository {
    fn sync(&self) -> Result<()> {
        let dir = self.dir();
        let dir_string = dir.display().to_string();
        let status = if dir.exists() {
            Command::new("git").current_dir(&dir).arg("pull").status()
        } else {
            std::fs::create_dir_all(&dir)
                .unwrap_or_else(|_| panic!("Failed to create dir {}", dir_string));
            Command::new("git")
                .current_dir(dir.parent().unwrap())
                .arg("clone")
                .arg(&self.git_url)
                .arg(dir)
                .status()
        };

        if let Some(code) = status?.code() {
            if code != 0 {
                return Err(anyhow!(
                    "Failed to pull remote '{}'. Consider remove dir '{}' and retry",
                    &self.git_url,
                    &dir_string
                ));
            }
        }

        Ok(())
    }
}

pub fn sync_repositories(config: &Config) -> Result<()> {
    config.sync_repositories()
}
