use anyhow::Context;
use dirs::home_dir;
use git2::Repository;
use regex::bytes::Regex;

use crate::models::host::Host;
use crate::Result;

pub struct Clone<'a> {
    pub host: Option<Host<'a>>,
    pub owner: Option<String>,
    pub repo: Option<String>,
}

impl<'a> Clone<'a> {
    pub fn new(host: Option<Host<'a>>, owner: Option<String>, repo: Option<String>) -> Self {
        Clone { host, owner, repo }
    }
    pub fn url(&self) -> String {
        format!(
            "{}/{}/{}",
            self.host.unwrap().url(),
            self.owner.as_ref().unwrap(),
            self.repo.as_ref().unwrap()
        )
    }
    pub fn clone(&self) -> Result<()> {
        let path = format!(
            "{}/Developer/{}/{}/{}",
            home_dir().unwrap().display(),
            self.host.unwrap(),
            self.owner.as_ref().unwrap(),
            self.repo.as_ref().unwrap()
        );
        println!(
            "Cloning {}/{} from {}...",
            self.owner.as_ref().unwrap(),
            self.repo.as_ref().unwrap(),
            self.host.unwrap()
        );
        Repository::clone(self.url().as_str(), &path)
            .with_context(|| "Failed to clone repository.")?;
        Ok(())
    }
    pub fn parse_url(url: &str, rx: Regex) -> Result<Clone> {
        let captures = rx.captures(url.as_ref()).unwrap();
        let host = captures
            .get(4)
            .map(|m| std::str::from_utf8(m.as_bytes()).unwrap())
            .with_context(|| "Could not map url.")?;
        let owner = captures
            .get(6)
            .map(|m| String::from_utf8(Vec::from(m.as_bytes())).unwrap())
            .with_context(|| "Could not map url.")?;
        let repo = captures
            .get(7)
            .map(|m| String::from_utf8(Vec::from(m.as_bytes())).unwrap())
            .with_context(|| "Could not map url.")?;
        Ok(Clone::new(
            Host::from(host.into()),
            Option::from(owner),
            Option::from(repo),
        ))
    }
}
