//! [TSM.ID].[11031972] -- Platform X Ecosystem
//! xcu-qcg-wasm -- Quantum Compute Graph WASM Runtime
#![deny(warnings)]

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

#[derive(Debug)]
pub enum WasmError {
    CompileFailed(String),
    RuntimeError(String),
    MemoryError(String),
    LinkError(String),
}

impl std::fmt::Display for WasmError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::CompileFailed(e) => write!(f, "Compile: {e}"),
            Self::RuntimeError(e) => write!(f, "Runtime: {e}"),
            Self::MemoryError(e) => write!(f, "Memory: {e}"),
            Self::LinkError(e) => write!(f, "Link: {e}"),
        }
    }
}
impl std::error::Error for WasmError {}
pub type Result<T> = std::result::Result<T, WasmError>;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WasmModule {
    pub name: String,
    pub bytecode: Vec<u8>,
    pub imports: Vec<String>,
    pub exports: Vec<String>,
    pub memory_pages: u32,
}

pub struct WasmRuntime {
    modules: Arc<Mutex<HashMap<String, WasmModule>>>,
    memory_limit: usize,
}

impl WasmRuntime {
    pub fn new(memory_limit: usize) -> Self {
        Self { modules: Arc::new(Mutex::new(HashMap::new())), memory_limit }
    }

    pub fn load_module(&self, module: WasmModule) -> Result<()> {
        if (module.memory_pages as usize) * 65536 > self.memory_limit {
            return Err(WasmError::MemoryError("exceeds limit".into()));
        }
        let mut mods = self.modules.lock().map_err(|e| WasmError::RuntimeError(e.to_string()))?;
        mods.insert(module.name.clone(), module);
        Ok(())
    }

    pub fn module_count(&self) -> usize { self.modules.lock().map(|m| m.len()).unwrap_or(0) }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_wasm_runtime() {
        let rt = WasmRuntime::new(1_048_576);
        rt.load_module(WasmModule {
            name: "test".into(), bytecode: vec![0, 0x61, 0x73, 0x6d],
            imports: vec![], exports: vec!["main".into()], memory_pages: 1,
        }).unwrap();
        assert_eq!(rt.module_count(), 1);
    }
}
