//! Policy Engine for RBAC
//!
//! Evaluates permissions based on roles and execution mode

use super::{Role, Resource, Action, Permission, ExecutionMode};
use std::collections::HashMap;

/// Policy engine for permission evaluation
pub struct PolicyEngine {
    mode: ExecutionMode,
    role_permissions: HashMap<Role, Vec<Permission>>,
}

impl PolicyEngine {
    /// Create a new policy engine
    pub fn new(mode: ExecutionMode) -> Self {
        let mut role_permissions = HashMap::new();

        // Pre-compute permissions for all roles
        for role in Role::all_roles() {
            role_permissions.insert(role, Permission::for_role(role));
        }

        Self {
            mode,
            role_permissions,
        }
    }

    /// Check if a role has permission for resource/action
    pub async fn check_permission(
        &self,
        role: Role,
        resource: Resource,
        action: Action,
    ) -> bool {
        // Solo mode allows everything
        if self.mode == ExecutionMode::Solo {
            return true;
        }

        // Check role permissions
        let permissions = self.role_permissions.get(&role).unwrap();
        permissions.contains(&Permission::new(resource, action))
    }

    /// Get all permissions for a role
    pub async fn get_role_permissions(&self, role: Role) -> Vec<Permission> {
        self.role_permissions.get(&role)
            .cloned()
            .unwrap_or_default()
    }

    /// Check if a role can access a specific environment
    pub fn can_access_environment(&self, role: Role, environment: &str) -> bool {
        match role {
            Role::Admin => true,
            Role::Operator => true,
            Role::Developer => environment == "dev" || environment == "staging",
            Role::ServiceAccount => true,
            Role::Auditor => true,
            Role::Viewer => false,
        }
    }

    /// Get permission level required for an action
    pub fn required_permission_level(&self, action: Action) -> u8 {
        match action {
            Action::Read => 20,
            Action::Audit => 40,
            Action::Execute => 50,
            Action::Configure => 60,
            Action::Create => 60,
            Action::Update => 60,
            Action::Deploy => 80,
            Action::Manage => 80,
            Action::Delete => 100,
        }
    }
}

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

    #[tokio::test]
    async fn test_solo_mode_allows_all() {
        let engine = PolicyEngine::new(ExecutionMode::Solo);

        assert!(engine.check_permission(
            Role::Viewer,
            Resource::Server,
            Action::Delete
        ).await);
    }

    #[tokio::test]
    async fn test_multi_user_permissions() {
        let engine = PolicyEngine::new(ExecutionMode::MultiUser);

        // Admin can delete
        assert!(engine.check_permission(
            Role::Admin,
            Resource::Server,
            Action::Delete
        ).await);

        // Viewer cannot delete
        assert!(!engine.check_permission(
            Role::Viewer,
            Resource::Server,
            Action::Delete
        ).await);
    }

    #[test]
    fn test_environment_access() {
        let engine = PolicyEngine::new(ExecutionMode::Enterprise);

        assert!(engine.can_access_environment(Role::Admin, "prod"));
        assert!(engine.can_access_environment(Role::Developer, "dev"));
        assert!(!engine.can_access_environment(Role::Developer, "prod"));
    }
}
