use crate::{
    bare::GitBare,
    cmd::{oid::ObjectId, tag::TagItem},
    errors::{GitError, GitResult},
};

impl GitBare {
    pub fn tag_info(&self, name: String) -> GitResult<TagItem> {
        let repo = self.gix_repo()?;
        let ref_str = format!("refs/tags/{name}");
        let mut reference = repo.find_reference(ref_str.as_str())?;

        let short_name = reference.name().shorten().to_string();
        let direct_id_hex = reference
            .target()
            .try_id()
            .map(|id| id.to_hex().to_string())
            .ok_or_else(|| {
                GitError::Internal("tag ref has no direct target".to_string())
            })?;

        let direct_gix_id: gix::hash::ObjectId =
            gix::hash::ObjectId::from_hex(direct_id_hex.as_bytes())
                .map_err(|e| GitError::InvalidOid(e.to_string()))?;
        let obj_header = repo.find_header(direct_gix_id)?;
        let is_annotated = obj_header.kind() == gix::object::Kind::Tag;
        let peeled_id = reference.peel_to_id()?;
        let peeled_hex = peeled_id.detach().to_hex().to_string();

        let (oid, target_oid) = if is_annotated {
            (ObjectId::new(direct_id_hex), ObjectId::new(peeled_hex))
        } else {
            let target_oid = ObjectId::new(direct_id_hex);
            (target_oid.clone(), target_oid)
        };

        let (message, tagger, tagger_email) = if is_annotated {
            let tag_obj = repo.find_tag(direct_gix_id)?;
            let decoded = tag_obj.decode()?;

            let message = decoded.message.to_string().trim_end().to_string();
            let msg = if message.is_empty() {
                None
            } else {
                Some(message)
            };

            let (tg_name, tg_email) = decoded
                .tagger()
                .ok()
                .flatten()
                .map(|s| (Some(s.name.to_string()), Some(s.email.to_string())))
                .unwrap_or((None, None));

            (msg, tg_name, tg_email)
        } else {
            (None, None, None)
        };

        Ok(TagItem {
            name: short_name,
            oid,
            target: target_oid,
            is_annotated,
            message,
            tagger,
            tagger_email,
        })
    }
}
