//! Shared ownership types for AiFastDb
//!
//! These types are used by both the core types module (MemoryNode, Entity)
//! and the federation module (OwnershipMeta, RecordPermissionChecker).
//! Defined here to avoid circular dependencies.

use serde::{Deserialize, Serialize};

/// Record visibility level
///
/// Controls who can see a record. Used in conjunction with ownership
/// to implement fine-grained access control (ABAC layer).
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum Visibility {
    /// Only the creator (owner) can see this record
    Private,
    /// All authenticated users can see this record
    Public,
    /// Only specified users can see this record
    Shared {
        /// User IDs that have access
        user_ids: Vec<String>,
    },
    /// Only users with specified roles can see this record
    RoleRestricted {
        /// Role names that have access
        roles: Vec<String>,
    },
}

impl Default for Visibility {
    fn default() -> Self {
        Visibility::Public
    }
}

impl std::fmt::Display for Visibility {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Visibility::Private => write!(f, "private"),
            Visibility::Public => write!(f, "public"),
            Visibility::Shared { user_ids } => write!(f, "shared({})", user_ids.join(",")),
            Visibility::RoleRestricted { roles } => {
                write!(f, "role_restricted({})", roles.join(","))
            }
        }
    }
}

/// Data protection level (Layer 0 — highest priority in permission checks)
///
/// Controls record mutability. Checked before ownership/visibility rules.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum ProtectionLevel {
    /// No protection — normal CRUD operations allowed
    None,
    /// Read-only — editing is blocked, but owner/admin can delete
    ReadOnly,
    /// Immutable — neither editing nor deletion allowed.
    /// Admin can downgrade via `downgrade_protection()` first.
    Immutable,
    /// System-level — only internal calls with `system_override` can modify.
    /// Cannot be set or changed via external API.
    System,
}

impl Default for ProtectionLevel {
    fn default() -> Self {
        ProtectionLevel::None
    }
}

impl std::fmt::Display for ProtectionLevel {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ProtectionLevel::None => write!(f, "none"),
            ProtectionLevel::ReadOnly => write!(f, "read_only"),
            ProtectionLevel::Immutable => write!(f, "immutable"),
            ProtectionLevel::System => write!(f, "system"),
        }
    }
}

/// Record-level permission type
///
/// Used in Collaborator to specify what operations a collaborator can perform.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum RecordPermission {
    /// Can read the record
    Read,
    /// Can edit/update the record content
    Write,
    /// Can delete the record
    Delete,
    /// Can modify visibility and manage collaborators
    Share,
}

/// A collaborator with specific record-level permissions
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Collaborator {
    /// Collaborator's user ID
    pub user_id: String,
    /// Granted record-level permissions
    pub permissions: Vec<RecordPermission>,
    /// When the permissions were granted (Unix ms)
    pub granted_at: i64,
    /// Who granted the permissions (usually the owner)
    pub granted_by: String,
}

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

    #[test]
    fn test_visibility_default() {
        assert_eq!(Visibility::default(), Visibility::Public);
    }

    #[test]
    fn test_visibility_serde() {
        let vis = Visibility::Shared {
            user_ids: vec!["user1".to_string(), "user2".to_string()],
        };
        let json = serde_json::to_string(&vis).unwrap();
        let parsed: Visibility = serde_json::from_str(&json).unwrap();
        assert_eq!(vis, parsed);
    }

    #[test]
    fn test_visibility_display() {
        assert_eq!(Visibility::Private.to_string(), "private");
        assert_eq!(Visibility::Public.to_string(), "public");
    }
}
