use crate::{
    bare::GitBare,
    cmd::{
        commit::{CommitMeta, CommitSignature},
        oid::ObjectId,
    },
    errors::GitResult,
};

impl GitBare {
    pub fn commit_info(&self, oid: ObjectId) -> GitResult<CommitMeta> {
        let repo = self.gix_repo()?;
        let gix_id: gix::hash::ObjectId = (&oid).try_into()?;

        let commit = repo.find_commit(gix_id)?;
        let decoded = commit.decode()?;

        let message_raw = commit.message_raw()?;
        let message = message_raw.to_string();
        let message = message.trim_end_matches('\n').to_string();
        let summary = message.lines().next().unwrap_or("").to_string();

        let author_sig = decoded.author()?;
        let author_time = author_sig.time()?;
        let committer_sig = decoded.committer()?;
        let committer_time = committer_sig.time()?;

        let tree_id = ObjectId::new(decoded.tree().to_hex().to_string());
        let parent_ids: Vec<ObjectId> = decoded
            .parents()
            .map(|id| ObjectId::new(id.to_hex().to_string()))
            .collect();

        let encoding = decoded
            .extra_headers()
            .find("encoding")
            .map(|v| v.to_string());

        Ok(CommitMeta {
            oid,
            message,
            summary,
            author: CommitSignature {
                name: author_sig.name.to_string(),
                email: author_sig.email.to_string(),
                time_secs: author_time.seconds as i64,
                offset_minutes: (author_time.offset / 60) as i32,
            },
            committer: CommitSignature {
                name: committer_sig.name.to_string(),
                email: committer_sig.email.to_string(),
                time_secs: committer_time.seconds as i64,
                offset_minutes: (committer_time.offset / 60) as i32,
            },
            tree_id,
            parent_ids,
            encoding,
        })
    }

    pub fn commit_exists(&self, oid: ObjectId) -> GitResult<bool> {
        let repo = self.gix_repo()?;
        let gix_id: gix::hash::ObjectId = (&oid).try_into()?;

        if !repo.has_object(gix_id) {
            return Ok(false);
        }

        let header = repo.find_header(gix_id)?;
        Ok(header.kind() == gix::object::Kind::Commit)
    }
}
