//! Storage layer for the Archivist.
//!
//! Provides file-based storage using NDJSON, JSON, and TSV formats,
//! along with content-addressable file storage for attachments.

use uuid::Uuid;

pub mod files;
pub mod json;
pub mod ndjson;
pub mod paths;
pub mod tsv;

// Re-export commonly used types and functions
pub use files::{get_file, store_file};
pub use json::{read_json, write_json};
pub use ndjson::{append_ndjson, read_ndjson, write_ndjson};
pub use paths::ArchivePaths;
pub use tsv::{read_connector_index, write_connector_index};

/// Check if a UUID is version 7 (time-ordered).
///
/// UUID version 7 is used throughout the archivist for scroll_ids and other
/// identifiers that need to be time-ordered and sortable.
///
/// # Examples
///
/// ```
/// use uuid::Uuid;
/// use dirigent_archivist::storage::is_uuid7;
///
/// let uuid7 = Uuid::now_v7();
/// assert!(is_uuid7(&uuid7));
///
/// let uuid4 = Uuid::new_v4();
/// assert!(!is_uuid7(&uuid4));
/// ```
pub fn is_uuid7(uuid: &Uuid) -> bool {
    uuid.get_version_num() == 7
}

/// Parse a string as UUID7, returning None for other versions.
///
/// This function ensures that only UUID version 7 identifiers are accepted,
/// rejecting other UUID versions (v1, v4, v5, etc.) that may be valid UUIDs
/// but don't meet the archivist's time-ordering requirements.
///
/// # Examples
///
/// ```
/// use uuid::Uuid;
/// use dirigent_archivist::storage::parse_uuid7;
///
/// // UUID7 string parses successfully
/// let uuid7_str = Uuid::now_v7().to_string();
/// assert!(parse_uuid7(&uuid7_str).is_some());
///
/// // UUID4 string is rejected
/// let uuid4_str = Uuid::new_v4().to_string();
/// assert!(parse_uuid7(&uuid4_str).is_none());
///
/// // Invalid UUID string is rejected
/// assert!(parse_uuid7("not-a-uuid").is_none());
/// ```
pub fn parse_uuid7(s: &str) -> Option<Uuid> {
    Uuid::parse_str(s).ok().filter(|u| is_uuid7(u))
}

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

    #[test]
    fn test_is_uuid7_accepts_uuid7() {
        let uuid7 = Uuid::now_v7();
        assert!(is_uuid7(&uuid7), "UUID7 should be recognized as version 7");
    }

    #[test]
    fn test_is_uuid7_rejects_uuid4() {
        let uuid4 = Uuid::new_v4();
        assert!(!is_uuid7(&uuid4), "UUID4 should not be recognized as version 7");
    }

    #[test]
    fn test_parse_uuid7_accepts_valid_uuid7_string() {
        let uuid7 = Uuid::now_v7();
        let uuid7_str = uuid7.to_string();
        let parsed = parse_uuid7(&uuid7_str);

        assert!(parsed.is_some(), "Valid UUID7 string should parse");
        assert_eq!(parsed.unwrap(), uuid7, "Parsed UUID should match original");
    }

    #[test]
    fn test_parse_uuid7_rejects_uuid4_string() {
        let uuid4 = Uuid::new_v4();
        let uuid4_str = uuid4.to_string();
        let parsed = parse_uuid7(&uuid4_str);

        assert!(parsed.is_none(), "UUID4 string should be rejected");
    }

    #[test]
    fn test_parse_uuid7_rejects_invalid_uuid_string() {
        let invalid_strings = vec![
            "not-a-uuid",
            "12345678-1234-1234-1234-123456789012-extra",
            "",
            "invalid",
        ];

        for invalid in invalid_strings {
            let parsed = parse_uuid7(invalid);
            assert!(parsed.is_none(), "Invalid UUID string '{}' should be rejected", invalid);
        }
    }
}
