//! [TSM.ID].[11031972] -- Platform X Ecosystem
//! xcu-omega -- Omega Unikernel Runtime Abstraction Layer
//! Provides bare-metal abstractions that compile on all platforms
#![deny(warnings)]
#![allow(dead_code)]

use serde::{Serialize, Deserialize};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

#[derive(Debug)]
pub enum OmegaError {
    BootFailed(String),
    HardwareFault(String),
    MemoryViolation(String),
    SchedulerFailed(String),
}

impl std::fmt::Display for OmegaError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::BootFailed(e) => write!(f, "Boot failed: {e}"),
            Self::HardwareFault(e) => write!(f, "HW fault: {e}"),
            Self::MemoryViolation(e) => write!(f, "Memory violation: {e}"),
            Self::SchedulerFailed(e) => write!(f, "Scheduler: {e}"),
        }
    }
}
impl std::error::Error for OmegaError {}
pub type Result<T> = std::result::Result<T, OmegaError>;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KernelConfig {
    pub stack_size: usize,
    pub heap_size: usize,
    pub tick_hz: u32,
    pub max_tasks: usize,
    pub params: HashMap<String, String>,
}

impl Default for KernelConfig {
    fn default() -> Self {
        Self { stack_size: 8192, heap_size: 1_048_576, tick_hz: 1000, max_tasks: 64, params: HashMap::new() }
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum KernelState { Boot, Init, Running, Idle, Panic, Shutdown }

pub struct MicroKernel {
    config: KernelConfig,
    state: Arc<Mutex<KernelState>>,
    uptime_ms: Arc<Mutex<u64>>,
    task_count: Arc<Mutex<usize>>,
}

impl MicroKernel {
    pub fn new(config: KernelConfig) -> Result<Self> {
        Ok(Self {
            config, state: Arc::new(Mutex::new(KernelState::Boot)),
            uptime_ms: Arc::new(Mutex::new(0)),
            task_count: Arc::new(Mutex::new(0)),
        })
    }

    pub fn boot(&self) -> Result<()> {
        let mut s = self.state.lock().map_err(|e| OmegaError::BootFailed(e.to_string()))?;
        *s = KernelState::Init;
        *s = KernelState::Running;
        Ok(())
    }

    pub fn shutdown(&self) -> Result<()> {
        let mut s = self.state.lock().map_err(|e| OmegaError::SchedulerFailed(e.to_string()))?;
        *s = KernelState::Shutdown;
        Ok(())
    }

    pub fn state(&self) -> Result<KernelState> {
        Ok(self.state.lock().map_err(|e| OmegaError::SchedulerFailed(e.to_string()))?.clone())
    }

    pub fn tick(&self) -> Result<u64> {
        let mut t = self.uptime_ms.lock().map_err(|e| OmegaError::SchedulerFailed(e.to_string()))?;
        *t += 1000 / self.config.tick_hz as u64;
        Ok(*t)
    }

    pub fn spawn_task(&self) -> Result<usize> {
        let mut c = self.task_count.lock().map_err(|e| OmegaError::SchedulerFailed(e.to_string()))?;
        if *c >= self.config.max_tasks { return Err(OmegaError::SchedulerFailed("max tasks reached".into())); }
        *c += 1;
        Ok(*c)
    }

    pub fn config(&self) -> &KernelConfig { &self.config }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_kernel() {
        let k = MicroKernel::new(KernelConfig::default()).unwrap();
        k.boot().unwrap();
        assert_eq!(k.state().unwrap(), KernelState::Running);
        k.tick().unwrap();
        k.spawn_task().unwrap();
        k.shutdown().unwrap();
        assert_eq!(k.state().unwrap(), KernelState::Shutdown);
    }
}
