//! Pure domain types, identifiers, and errors for Sourse.
//!
//! This crate defines the foundational types shared across all Sourse crates.
//! It has no async runtime, filesystem, or network dependencies.

/// The Sourse version string for the current bootstrap.
pub const VERSION: &str = "0.0.1-pre-alpha.0";

/// Strongly typed object ID newtype.
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct ObjectId(pub String);

/// Strongly typed commit ID newtype.
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct CommitId(pub String);

/// Strongly typed segment ID newtype.
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct SegmentId(pub String);

/// Sourse error type for domain-level failures.
#[derive(Debug, thiserror::Error)]
pub enum SourseError {
    /// An invalid or malformed identifier was provided.
    #[error("invalid identifier: {0}")]
    InvalidId(String),

    /// A requested resource was not found.
    #[error("not found: {0}")]
    NotFound(String),

    /// A domain invariant was violated.
    #[error("invariant violation: {0}")]
    InvariantViolation(String),
}

/// Result type alias for Sourse operations.
pub type SourseResult<T> = Result<T, SourseError>;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn object_id_equality() {
        let a = ObjectId("abc".to_string());
        let b = ObjectId("abc".to_string());
        assert_eq!(a, b);
    }

    #[test]
    fn commit_id_distinct() {
        let a = CommitId("aaa".to_string());
        let b = CommitId("bbb".to_string());
        assert_ne!(a, b);
    }

    #[test]
    fn segment_id_serialization() {
        let id = SegmentId("seg-1".to_string());
        let json = serde_json::to_string(&id).unwrap();
        let id2: SegmentId = serde_json::from_str(&json).unwrap();
        assert_eq!(id, id2);
    }

    #[test]
    fn sourse_error_display() {
        let err = SourseError::InvalidId("bad id".to_string());
        assert_eq!(format!("{err}"), "invalid identifier: bad id");
        let err = SourseError::NotFound("missing".to_string());
        assert_eq!(format!("{err}"), "not found: missing");
        let err = SourseError::InvariantViolation("broken".to_string());
        assert_eq!(format!("{err}"), "invariant violation: broken");
    }

    #[test]
    fn version_constant() {
        assert!(!VERSION.is_empty());
    }
}
