#![deny(warnings)]
#![allow(dead_code)]
//! [TSM.ID].[11031972] -- Platform X Ecosystem
//! xcu-tartarus -- Maximum Isolation Sandbox
//! Process quarantine with resource limits and syscall filtering

use std::collections::HashSet;

#[derive(Debug)]
pub enum TartarusError {
    QuarantineFailed(String),
    ResourceExceeded(String),
    DeniedSyscall(String),
}
impl std::fmt::Display for TartarusError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self { Self::QuarantineFailed(e) => write!(f, "Quarantine: {e}"),
            Self::ResourceExceeded(e) => write!(f, "Resource: {e}"),
            Self::DeniedSyscall(e) => write!(f, "Denied: {e}"), }
    }
}
impl std::error::Error for TartarusError {}

#[derive(Debug, Clone)]
pub struct ResourceLimits {
    pub max_memory_mb: u64,
    pub max_cpu_percent: f64,
    pub max_open_files: u32,
    pub max_network_bytes: u64,
    pub max_execution_secs: u64,
}
impl Default for ResourceLimits {
    fn default() -> Self {
        Self { max_memory_mb: 256, max_cpu_percent: 25.0, max_open_files: 64,
            max_network_bytes: 10 * 1024 * 1024, max_execution_secs: 300 }
    }
}

#[derive(Debug, Clone)]
pub struct ResourceUsage {
    pub memory_mb: u64,
    pub cpu_percent: f64,
    pub open_files: u32,
    pub network_bytes: u64,
    pub elapsed_secs: u64,
}

#[derive(Debug, Clone, PartialEq)]
pub enum IsolationLevel { Minimal, Standard, Maximum, Solitary }

#[derive(Debug)]
pub struct TartarusCell {
    pub cell_id: String,
    pub isolation: IsolationLevel,
    pub limits: ResourceLimits,
    allowed_syscalls: HashSet<String>,
    denied_syscalls: HashSet<String>,
    violation_count: u32,
}

impl TartarusCell {
    pub fn new(cell_id: String, isolation: IsolationLevel) -> Self {
        let mut allowed = HashSet::new();
        let mut denied = HashSet::new();
        match isolation {
            IsolationLevel::Minimal => {
                allowed.insert("read".into()); allowed.insert("write".into());
                allowed.insert("open".into()); allowed.insert("close".into());
                allowed.insert("mmap".into()); allowed.insert("brk".into());
            }
            IsolationLevel::Standard => {
                allowed.insert("read".into()); allowed.insert("write".into());
                allowed.insert("open".into()); allowed.insert("close".into());
                denied.insert("exec".into()); denied.insert("fork".into());
                denied.insert("socket".into());
            }
            IsolationLevel::Maximum | IsolationLevel::Solitary => {
                allowed.insert("read".into()); allowed.insert("write".into());
                denied.insert("exec".into()); denied.insert("fork".into());
                denied.insert("socket".into()); denied.insert("connect".into());
                denied.insert("bind".into()); denied.insert("listen".into());
                denied.insert("open".into()); denied.insert("mmap".into());
            }
        }
        let limits = match isolation {
            IsolationLevel::Minimal => ResourceLimits { max_memory_mb: 1024, max_cpu_percent: 50.0, ..Default::default() },
            IsolationLevel::Standard => ResourceLimits::default(),
            IsolationLevel::Maximum => ResourceLimits { max_memory_mb: 128, max_cpu_percent: 10.0, max_open_files: 16, max_network_bytes: 0, max_execution_secs: 60 },
            IsolationLevel::Solitary => ResourceLimits { max_memory_mb: 64, max_cpu_percent: 5.0, max_open_files: 4, max_network_bytes: 0, max_execution_secs: 30 },
        };
        Self { cell_id, isolation, limits, allowed_syscalls: allowed, denied_syscalls: denied, violation_count: 0 }
    }

    pub fn check_syscall(&mut self, syscall: &str) -> Result<bool, TartarusError> {
        if self.denied_syscalls.contains(syscall) {
            self.violation_count += 1;
            return Err(TartarusError::DeniedSyscall(format!("{syscall} denied in {:?} (violation #{})", self.isolation, self.violation_count)));
        }
        Ok(self.allowed_syscalls.contains(syscall))
    }

    pub fn check_resources(&self, usage: &ResourceUsage) -> Result<(), TartarusError> {
        if usage.memory_mb > self.limits.max_memory_mb {
            return Err(TartarusError::ResourceExceeded(format!("Memory {}MB > {}MB", usage.memory_mb, self.limits.max_memory_mb)));
        }
        if usage.cpu_percent > self.limits.max_cpu_percent {
            return Err(TartarusError::ResourceExceeded(format!("CPU {}% > {}%", usage.cpu_percent, self.limits.max_cpu_percent)));
        }
        if usage.open_files > self.limits.max_open_files {
            return Err(TartarusError::ResourceExceeded(format!("Files {} > {}", usage.open_files, self.limits.max_open_files)));
        }
        if usage.network_bytes > self.limits.max_network_bytes {
            return Err(TartarusError::ResourceExceeded(format!("Network {}B > {}B", usage.network_bytes, self.limits.max_network_bytes)));
        }
        if usage.elapsed_secs > self.limits.max_execution_secs {
            return Err(TartarusError::ResourceExceeded(format!("Time {}s > {}s", usage.elapsed_secs, self.limits.max_execution_secs)));
        }
        Ok(())
    }

    pub fn should_terminate(&self) -> bool {
        self.violation_count >= 3
    }

    pub fn violations(&self) -> u32 { self.violation_count }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_solitary_blocks_everything() {
        let mut cell = TartarusCell::new("prison-1".into(), IsolationLevel::Solitary);
        assert!(cell.check_syscall("exec").is_err());
        assert!(cell.check_syscall("fork").is_err());
        assert!(cell.check_syscall("socket").is_err());
        assert!(cell.check_syscall("read").is_ok());
    }
    #[test]
    fn test_resource_exceeded() {
        let cell = TartarusCell::new("cell-1".into(), IsolationLevel::Maximum);
        let usage = ResourceUsage { memory_mb: 200, cpu_percent: 5.0, open_files: 4, network_bytes: 0, elapsed_secs: 10 };
        assert!(cell.check_resources(&usage).is_err());
    }
    #[test]
    fn test_auto_terminate() {
        let mut cell = TartarusCell::new("bad-actor".into(), IsolationLevel::Standard);
        let _ = cell.check_syscall("exec");
        let _ = cell.check_syscall("fork");
        let _ = cell.check_syscall("socket");
        assert!(cell.should_terminate());
    }
}
