use gix_hash::ObjectId;
use crate::{FullName, Target};
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Reference {
    pub name: FullName,
    pub target: Target,
    pub peeled: Option<ObjectId>,
}
mod convert {
    use gix_hash::ObjectId;
    use crate::{
        raw::Reference,
        store_impl::{file::loose, packed},
        Target,
    };
    impl From<Reference> for loose::Reference {
        fn from(value: Reference) -> Self {
            loose::Reference {
                name: value.name,
                target: value.target,
            }
        }
    }
    impl From<loose::Reference> for Reference {
        fn from(value: loose::Reference) -> Self {
            Reference {
                name: value.name,
                target: value.target,
                peeled: None,
            }
        }
    }
    impl<'p> From<packed::Reference<'p>> for Reference {
        fn from(value: packed::Reference<'p>) -> Self {
            Reference {
                name: value.name.into(),
                target: Target::Peeled(value.target()),
                peeled: value
                    .object
                    .map(|hex| ObjectId::from_hex(hex).expect("parser validation")),
            }
        }
    }
}
mod access {
    use gix_object::bstr::ByteSlice;
    use crate::{raw::Reference, FullNameRef, Namespace, Target};
    impl Reference {
        pub fn kind(&self) -> crate::Kind {
            self.target.kind()
        }
        pub fn name_without_namespace(&self, namespace: &Namespace) -> Option<&FullNameRef> {
            self.name
                .0
                .as_bstr()
                .strip_prefix(namespace.0.as_bytes())
                .map(|stripped| FullNameRef::new_unchecked(stripped.as_bstr()))
        }
        pub fn strip_namespace(&mut self, namespace: &Namespace) -> &mut Self {
            self.name.strip_namespace(namespace);
            if let Target::Symbolic(name) = &mut self.target {
                name.strip_namespace(namespace);
            }
            self
        }
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn size_of_reference() {
        assert_eq!(
            std::mem::size_of::<Reference>(),
            80,
            "let's not let it change size undetected"
        );
    }
}