//! Capability-based security sandbox for Glyph runtime
//!
//! This crate enforces the capability-based security model for Glyph programs.
//! Programs must declare required capabilities upfront, and the sandbox ensures
//! that only authorized operations are executed.

use std::collections::HashSet;
use std::time::{Duration, Instant};
use thiserror::Error;

#[derive(Debug, Error)]
pub enum SandboxError {
    #[error("capability '{0}' not granted")]
    CapabilityNotGranted(String),

    #[error("resource limit exceeded: {0}")]
    ResourceLimitExceeded(String),

    #[error("operation timed out")]
    Timeout,

    #[error("operation rate limited")]
    RateLimited,
}

/// Security capabilities that can be granted to programs
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Capability {
    /// Allow voice synthesis
    Voice,
    /// Allow network access
    Network,
    /// Allow file system access
    FileSystem,
    /// Allow display operations
    Display,
    /// Allow user interaction
    UserInteraction,
}

/// Resource limits for sandboxed execution
#[derive(Debug, Clone)]
pub struct ResourceLimits {
    /// Maximum memory usage in bytes
    pub max_memory: usize,
    /// Maximum execution time
    pub max_execution_time: Duration,
    /// Maximum number of operations per minute
    pub rate_limit: Option<u32>,
}

impl Default for ResourceLimits {
    fn default() -> Self {
        Self {
            max_memory: 100 * 1024 * 1024, // 100MB
            max_execution_time: Duration::from_secs(30),
            rate_limit: Some(60), // 60 ops/minute
        }
    }
}

/// Security sandbox for Glyph program execution
pub struct Sandbox {
    granted_capabilities: HashSet<Capability>,
    resource_limits: ResourceLimits,
    start_time: Instant,
}

impl Sandbox {
    /// Create a new sandbox with specified capabilities and limits
    pub fn new(capabilities: Vec<Capability>, limits: ResourceLimits) -> Self {
        Self {
            granted_capabilities: capabilities.into_iter().collect(),
            resource_limits: limits,
            start_time: Instant::now(),
        }
    }

    /// Check if a capability is granted
    pub fn check_capability(&self, capability: &Capability) -> Result<(), SandboxError> {
        if self.granted_capabilities.contains(capability) {
            Ok(())
        } else {
            Err(SandboxError::CapabilityNotGranted(format!("{capability:?}")))
        }
    }

    /// Check if execution time limit has been exceeded
    pub fn check_timeout(&self) -> Result<(), SandboxError> {
        if self.start_time.elapsed() > self.resource_limits.max_execution_time {
            Err(SandboxError::Timeout)
        } else {
            Ok(())
        }
    }
}
