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

impl GitBare {
    pub fn tag_list(&self) -> GitResult<Vec<TagItem>> {
        let repo = self.gix_repo()?;
        let platform = repo.references()?;
        let tags_iter = platform.tags()?;

        let mut items = Vec::new();
        for ref_result in tags_iter {
            let mut reference = ref_result?;
            let name = reference.name().shorten().to_string();
            let direct_id_hex = reference
                .target()
                .try_id()
                .map(|id| id.to_hex().to_string())
                .ok_or_else(|| {
                    crate::errors::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| {
                        crate::errors::GitError::InvalidOid(e.to_string())
                    })?;
            let is_annotated = repo
                .find_header(direct_gix_id)
                .ok()
                .is_some_and(|h| h.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)
            };

            items.push(TagItem {
                name,
                oid,
                target: target_oid,
                is_annotated,
                message: None,
                tagger: None,
                tagger_email: None,
            });
        }

        Ok(items)
    }
}
