use super::*;
use crate::GitError;

impl Debug for FileCommit {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        let w = &mut f.debug_struct("FileCommit");
        w.field("path", &self.url.path());
        w.field("commits", &self.inner.values());
        w.finish()
    }
}

impl AddAssign<Self> for FileCommit {
    fn add_assign(&mut self, rhs: Self) {
        for (time, commit) in rhs.inner {
            match self.inner.get_mut(&time) {
                None => {
                    self.inner.insert(time, commit);
                }
                Some(s) => s.lines += commit.lines,
            }
        }
    }
}

impl FileCommit {
    pub fn new(repo: &Repository, path: &Path) -> Result<Self> {
        let file = repo.blame_file(Self::relative_path(path, repo.path())?.as_path(), None)?;
        let mut record = FileCommit { url: Url::from_file_path(&path)?, inner: Default::default() };
        for i in file.iter() {
            record.insert(FileCommitItem::from(i));
        }
        return Ok(record);
    }

    fn relative_path(path: &Path, base: &Path) -> Result<PathBuf> {
        let s = match diff_paths(path, base).map(|s| s.to_path_buf()) {
            None => return Err(GitError::from(())),
            Some(s) => s.to_string_lossy().trim_start_matches("..\\").replace("\\", "/"),
        };
        Ok(PathBuf::from(s))
    }
    #[inline]
    pub fn get_url(&self) -> Url {
        self.url.to_owned()
    }
    #[inline]
    pub fn get_path(&self) -> PathBuf {
        PathBuf::from(self.url.path())
    }
    #[inline]
    pub fn get_extension(&self) -> Option<String> {
        self.get_path().extension().map(|s| s.to_string_lossy().to_string())
    }
}

impl FileCommit {
    pub fn insert(&mut self, item: FileCommitItem) {
        let key = item.time.to_owned();
        match self.inner.get_mut(&key) {
            None => {
                self.inner.insert(key, item);
            }
            Some(s) => s.lines += item.lines,
        }
    }
}