//! Deterministic UUID generation for system-provided resources
//!
//! Used ONLY for system default tags and built-in resources that need
//! consistent UUIDs across all Spacedrive installations.
//!
//! WARNING: User-created tags should use random UUIDs to support the
//! semantic tagging system's polymorphic naming (multiple tags with
//! the same name in different contexts).

use uuid::Uuid;

/// Usage Example:
/// ```rust,ignore
/// // System tags - use deterministic UUIDs for consistency
/// let system_tag = SemanticTag {
///     uuid: system_tags::SCREENSHOT_TAG_UUID.clone(),
///     canonical_name: "Screenshot".to_string(),
///     tag_type: TagType::System,
///     ...
/// };
///
/// // User tags - use random UUIDs for polymorphic naming
/// let user_tag = SemanticTag {
///     uuid: Uuid::new_v4(), // Random!
///     canonical_name: "Vacation".to_string(),
///     namespace: Some("Travel".to_string()),
///     tag_type: TagType::Standard,
///     ...
/// };
/// ```

/// Namespace for tag UUIDs
pub const TAG_NAMESPACE: Uuid = Uuid::from_bytes([
	0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
]);

/// Namespace for album UUIDs
pub const ALBUM_NAMESPACE: Uuid = Uuid::from_bytes([
	0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
]);

/// Generate deterministic UUID for a system default tag
///
/// This should ONLY be used for built-in system tags that ship with
/// Spacedrive. User-created tags must use random UUIDs.
///
/// # Example
/// ```rust,ignore
/// // System tags that need consistent UUIDs
/// let uuid = deterministic_system_tag_uuid("System");
/// let uuid = deterministic_system_tag_uuid("Screenshot");
/// let uuid = deterministic_system_tag_uuid("Download");
/// ```
pub fn deterministic_system_tag_uuid(name: &str) -> Uuid {
	Uuid::new_v5(&TAG_NAMESPACE, name.as_bytes())
}

/// Generate deterministic UUID for an album name
/// System default tags that ship with every Spacedrive installation
///
/// These tags should be created during library initialization:
/// ```rust,ignore
/// // In library creation/initialization
/// for (name, uuid) in system_tags::get_all() {
///     let tag = SemanticTag {
///         uuid: uuid,
///         canonical_name: name,
///         tag_type: TagType::System,
///         namespace: Some("System".to_string()),
///         privacy_level: PrivacyLevel::Normal,
///         // ... other fields
///     };
///     tag.insert_or_ignore(db).await?;
/// }
/// ```
pub mod system_tags {
	use super::*;

	// File type tags
	pub fn system() -> Uuid {
		deterministic_system_tag_uuid("System")
	}
	pub fn screenshot() -> Uuid {
		deterministic_system_tag_uuid("Screenshot")
	}
	pub fn download() -> Uuid {
		deterministic_system_tag_uuid("Download")
	}
	pub fn document() -> Uuid {
		deterministic_system_tag_uuid("Document")
	}
	pub fn image() -> Uuid {
		deterministic_system_tag_uuid("Image")
	}
	pub fn video() -> Uuid {
		deterministic_system_tag_uuid("Video")
	}
	pub fn audio() -> Uuid {
		deterministic_system_tag_uuid("Audio")
	}

	// Special behavior tags
	pub fn hidden() -> Uuid {
		deterministic_system_tag_uuid(".hidden")
	}
	pub fn archive() -> Uuid {
		deterministic_system_tag_uuid(".archive")
	}
	pub fn favorite() -> Uuid {
		deterministic_system_tag_uuid("Favorite")
	}

	/// Get all system tags for library initialization
	pub fn get_all() -> Vec<(&'static str, Uuid)> {
		vec![
			("System", system()),
			("Screenshot", screenshot()),
			("Download", download()),
			("Document", document()),
			("Image", image()),
			("Video", video()),
			("Audio", audio()),
			(".hidden", hidden()),
			(".archive", archive()),
			("Favorite", favorite()),
		]
	}
}

/// Generate deterministic UUID for a system default album
///
/// Similar to tags, only for system-provided albums.
pub fn deterministic_system_album_uuid(name: &str) -> Uuid {
	Uuid::new_v5(&ALBUM_NAMESPACE, name.as_bytes())
}

/// Generate deterministic UUID for library-scoped default entities
///
/// This is the polymorphic way to create default entities (spaces, groups, etc.)
/// that need consistent UUIDs across all devices sharing a library.
///
/// Uses library_id as the namespace, so:
/// - Same library + same entity_type + same name = same UUID on all devices
/// - Different libraries = different UUIDs (no cross-library collisions)
///
/// # Example
/// ```rust,ignore
/// // Default space for this library
/// let space_id = deterministic_library_default_uuid(library_id, "space", "All Devices");
///
/// // Default group within that space
/// let group_id = deterministic_library_default_uuid(library_id, "space_group", "Locations");
///
/// // Default item
/// let item_id = deterministic_library_default_uuid(library_id, "space_item", "Overview");
/// ```
pub fn deterministic_library_default_uuid(library_id: Uuid, entity_type: &str, name: &str) -> Uuid {
	Uuid::new_v5(&library_id, format!("{}:{}", entity_type, name).as_bytes())
}

/// When to use deterministic vs random UUIDs:
///
/// USE DETERMINISTIC UUIDs FOR:
/// - System default tags that ship with Spacedrive
/// - Built-in tags referenced by code (e.g., HIDDEN_TAG_UUID)
/// - System albums like "Recent Imports" or "Quick Access"
/// - Any resource that needs the SAME UUID across ALL installations
///
/// USE RANDOM UUIDs (Uuid::new_v4()) FOR:
/// - ALL user-created tags
/// - ALL user-created albums  
/// - Any resource that supports polymorphic naming
/// - Any resource where multiple instances with the same name are valid
///
/// The semantic tagging system REQUIRES random UUIDs to support multiple
/// tags with the same name in different contexts (e.g., "Phoenix" as a city
/// vs "Phoenix" as mythology).

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

	#[test]
	fn test_deterministic_system_tag_uuid() {
		let uuid1 = deterministic_system_tag_uuid("System");
		let uuid2 = deterministic_system_tag_uuid("System");

		// Same system tag = same UUID across all installations
		assert_eq!(uuid1, uuid2);

		// Different system tags = different UUIDs
		let uuid3 = deterministic_system_tag_uuid("Screenshot");
		assert_ne!(uuid1, uuid3);

		// Verify known system tags have consistent UUIDs
		assert_eq!(
			system_tags::system(),
			deterministic_system_tag_uuid("System")
		);
		assert_eq!(
			system_tags::screenshot(),
			deterministic_system_tag_uuid("Screenshot")
		);
	}

	#[test]
	fn test_deterministic_system_album_uuid() {
		let uuid1 = deterministic_system_album_uuid("Recent Imports");
		let uuid2 = deterministic_system_album_uuid("Recent Imports");

		assert_eq!(uuid1, uuid2);
	}

	#[test]
	fn test_deterministic_library_default_uuid() {
		let library_a = Uuid::new_v4();
		let library_b = Uuid::new_v4();

		// Same library + same entity = same UUID
		let space1 = deterministic_library_default_uuid(library_a, "space", "All Devices");
		let space2 = deterministic_library_default_uuid(library_a, "space", "All Devices");
		assert_eq!(space1, space2);

		// Different libraries = different UUIDs
		let space3 = deterministic_library_default_uuid(library_b, "space", "All Devices");
		assert_ne!(space1, space3);

		// Different entity types = different UUIDs
		let group = deterministic_library_default_uuid(library_a, "space_group", "All Devices");
		assert_ne!(space1, group);

		// Different names = different UUIDs
		let other_space = deterministic_library_default_uuid(library_a, "space", "Other Space");
		assert_ne!(space1, other_space);
	}
}
