dist_agent_lang 1.0.3

A hybrid programming language for decentralized and centralized network integration
use std::collections::HashMap;
use std::sync::{Mutex, OnceLock};

/// Capability ABI - Interface for capability-based access control
/// 
/// This provides a namespace-based approach to capability operations:
/// - cap::create(resource, permissions) - Create new capability
/// - cap::grant(capability, principal) - Grant capability to principal
/// - cap::check(capability, operation) - Check if operation is allowed

#[derive(Debug, Clone)]
pub struct Capability {
    pub id: String,
    pub resource: String,
    pub permissions: Vec<String>,
    pub expires_at: Option<i64>,
}

#[derive(Debug, Clone)]
pub struct Principal {
    pub id: String,
    pub name: String,
    pub capabilities: Vec<String>,
}

#[derive(Debug, Clone)]
pub struct CapabilityRequest {
    pub resource: String,
    pub operation: String,
    pub principal_id: String,
}

impl Capability {
    pub fn new(id: String, resource: String, permissions: Vec<String>) -> Self {
        Self {
            id,
            resource,
            permissions,
            expires_at: None,
        }
    }
    
    pub fn with_expiry(mut self, expires_at: i64) -> Self {
        self.expires_at = Some(expires_at);
        self
    }
    
    pub fn has_permission(&self, permission: &str) -> bool {
        self.permissions.contains(&permission.to_string())
    }
    
    pub fn is_expired(&self) -> bool {
        if let Some(expires_at) = self.expires_at {
            expires_at < current_time_secs()
        } else {
            false
        }
    }
}

/// Current Unix timestamp in seconds (for expiry checks).
fn current_time_secs() -> i64 {
    std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .map(|d| d.as_secs() as i64)
        .unwrap_or(0)
}

/// In-memory capability registry: created capabilities and principal grants.
struct CapRegistry {
    capabilities: HashMap<String, Capability>,
    principal_grants: HashMap<String, Vec<String>>,
}

fn get_registry() -> std::sync::MutexGuard<'static, CapRegistry> {
    static REG: OnceLock<Mutex<CapRegistry>> = OnceLock::new();
    REG.get_or_init(|| Mutex::new(CapRegistry {
        capabilities: HashMap::new(),
        principal_grants: HashMap::new(),
    }))
    .lock()
    .unwrap()
}

impl Principal {
    pub fn new(id: String, name: String) -> Self {
        Self {
            id,
            name,
            capabilities: Vec::new(),
        }
    }
    
    pub fn with_capability(mut self, capability_id: String) -> Self {
        self.capabilities.push(capability_id);
        self
    }
    
    pub fn has_capability(&self, capability_id: &str) -> bool {
        self.capabilities.contains(&capability_id.to_string())
    }
}

/// Create new capability
pub fn create(resource: &str, permissions: Vec<&str>) -> Result<Capability, String> {
    // Mock implementation - in real system this would create capability objects
    if resource.is_empty() {
        return Err("Resource cannot be empty".to_string());
    }
    
    if permissions.is_empty() {
        return Err("At least one permission is required".to_string());
    }
    
    let capability_id = format!("cap_{}_{}", resource.replace("/", "_"), 1756744707);
    let permissions_vec: Vec<String> = permissions.iter().map(|&s| s.to_string()).collect();
    
    Ok(Capability::new(capability_id, resource.to_string(), permissions_vec))
}

/// Grant capability to principal and update registry.
pub fn grant(capability: &Capability, principal: &mut Principal) -> Result<bool, String> {
    if capability.is_expired() {
        return Err("Cannot grant expired capability".to_string());
    }
    if principal.has_capability(&capability.id) {
        return Err("Principal already has this capability".to_string());
    }

    let mut reg = get_registry();
    reg.capabilities.insert(capability.id.clone(), capability.clone());
    reg.principal_grants
        .entry(principal.id.clone())
        .or_default()
        .push(capability.id.clone());
    *principal = principal.clone().with_capability(capability.id.clone());
    Ok(true)
}

/// Check if operation is allowed by looking up capability registry for the principal.
pub fn check(request: CapabilityRequest) -> Result<bool, String> {
    let reg = get_registry();
    let cap_ids = reg.principal_grants.get(&request.principal_id);
    let Some(cap_ids) = cap_ids else {
        return Ok(false);
    };
    for cap_id in cap_ids {
        if let Some(cap) = reg.capabilities.get(cap_id) {
            if cap.is_expired() {
                continue;
            }
            if cap.resource == request.resource && cap.has_permission(&request.operation) {
                return Ok(true);
            }
        }
    }
    // Fallback: built-in rules when no matching capability in registry
    match request.resource.as_str() {
        "user_data" => {
            if request.operation == "read" {
                Ok(true)
            } else if request.operation == "write" {
                Ok(false)
            } else {
                Err("Unknown operation".to_string())
            }
        }
        "system_config" => {
            if request.operation == "read" {
                Ok(true)
            } else {
                Ok(false)
            }
        }
        _ => Ok(false),
    }
}

/// Create a new principal
pub fn create_principal(id: String, name: String) -> Principal {
    Principal::new(id, name)
}

/// Create a capability request
pub fn create_capability_request(resource: String, operation: String, principal_id: String) -> CapabilityRequest {
    CapabilityRequest {
        resource,
        operation,
        principal_id,
    }
}