//! [TSM.ID].[11031972] -- Platform X Ecosystem
//! xcu-core -- XCU Core Engine Foundation
//! Central orchestrator for the Platform X ecosystem
#![deny(warnings)]
#![allow(dead_code)]

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

#[derive(Debug)]
pub enum CoreError {
    InitFailed(String),
    ModuleNotFound(String),
    ConfigError(String),
    RuntimeError(String),
    ShutdownError(String),
}

impl std::fmt::Display for CoreError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::InitFailed(e) => write!(f, "Init failed: {e}"),
            Self::ModuleNotFound(e) => write!(f, "Module not found: {e}"),
            Self::ConfigError(e) => write!(f, "Config error: {e}"),
            Self::RuntimeError(e) => write!(f, "Runtime error: {e}"),
            Self::ShutdownError(e) => write!(f, "Shutdown error: {e}"),
        }
    }
}
impl std::error::Error for CoreError {}
pub type Result<T> = std::result::Result<T, CoreError>;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CoreConfig {
    pub instance_id: String,
    pub modules: Vec<String>,
    pub params: HashMap<String, String>,
    pub max_workers: usize,
}

impl Default for CoreConfig {
    fn default() -> Self {
        Self {
            instance_id: "xcu-core-0".to_string(),
            modules: Vec::new(),
            params: HashMap::new(),
            max_workers: num_cpus(),
        }
    }
}

fn num_cpus() -> usize {
    std::thread::available_parallelism().map(|n| n.get()).unwrap_or(4)
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum CoreState { Booting, Ready, Running, Degraded, ShuttingDown, Stopped }

pub struct CoreEngine {
    config: CoreConfig,
    state: Arc<Mutex<CoreState>>,
    module_registry: Arc<Mutex<HashMap<String, ModuleInfo>>>,
    start_time: std::time::Instant,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModuleInfo {
    pub name: String,
    pub version: String,
    pub status: String,
}

impl CoreEngine {
    pub fn new(config: CoreConfig) -> Result<Self> {
        Ok(Self {
            config,
            state: Arc::new(Mutex::new(CoreState::Booting)),
            module_registry: Arc::new(Mutex::new(HashMap::new())),
            start_time: std::time::Instant::now(),
        })
    }

    pub fn init(&self) -> Result<()> {
        tracing::info!("XCU Core initializing: {}", self.config.instance_id);
        let mut s = self.state.lock().map_err(|e| CoreError::InitFailed(e.to_string()))?;
        *s = CoreState::Ready;
        Ok(())
    }

    pub fn start(&self) -> Result<()> {
        let mut s = self.state.lock().map_err(|e| CoreError::RuntimeError(e.to_string()))?;
        *s = CoreState::Running;
        tracing::info!("XCU Core running with {} workers", self.config.max_workers);
        Ok(())
    }

    pub fn shutdown(&self) -> Result<()> {
        let mut s = self.state.lock().map_err(|e| CoreError::ShutdownError(e.to_string()))?;
        *s = CoreState::ShuttingDown;
        tracing::info!("XCU Core shutting down gracefully");
        *s = CoreState::Stopped;
        Ok(())
    }

    pub fn register_module(&self, info: ModuleInfo) -> Result<()> {
        let mut reg = self.module_registry.lock().map_err(|e| CoreError::RuntimeError(e.to_string()))?;
        reg.insert(info.name.clone(), info);
        Ok(())
    }

    pub fn state(&self) -> Result<CoreState> {
        Ok(self.state.lock().map_err(|e| CoreError::RuntimeError(e.to_string()))?.clone())
    }

    pub fn uptime_secs(&self) -> u64 { self.start_time.elapsed().as_secs() }
    pub fn module_count(&self) -> usize { self.module_registry.lock().map(|r| r.len()).unwrap_or(0) }
    pub fn config(&self) -> &CoreConfig { &self.config }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_core_lifecycle() {
        let engine = CoreEngine::new(CoreConfig::default()).unwrap();
        engine.init().unwrap();
        assert_eq!(engine.state().unwrap(), CoreState::Ready);
        engine.start().unwrap();
        assert_eq!(engine.state().unwrap(), CoreState::Running);
        engine.register_module(ModuleInfo {
            name: "test".into(), version: "0.1.0".into(), status: "ok".into()
        }).unwrap();
        assert_eq!(engine.module_count(), 1);
        engine.shutdown().unwrap();
        assert_eq!(engine.state().unwrap(), CoreState::Stopped);
    }
}
