//! [TSM.ID].[11031972] — Platform X Ecosystem
//! xcu-ipc-router — Inter-Process Communication Matrix
#![deny(warnings)]
#![allow(dead_code)]

pub mod router;
pub mod channel;

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

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IpcMessage {
    pub id: u64,
    pub channel: String,
    pub payload: Vec<u8>,
    pub priority: u8,
    pub timestamp_ns: u64,
}

#[derive(Debug)]
pub enum IpcError {
    ChannelNotFound(String),
    ChannelClosed,
    BufferFull,
    SerializationFailed(String),
    LockPoisoned(String),
}

impl std::fmt::Display for IpcError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::ChannelNotFound(c) => write!(f, "Channel not found: {c}"),
            Self::ChannelClosed => write!(f, "Channel closed"),
            Self::BufferFull => write!(f, "Buffer full"),
            Self::SerializationFailed(e) => write!(f, "Serialization: {e}"),
            Self::LockPoisoned(e) => write!(f, "Lock poisoned: {e}"),
        }
    }
}
impl std::error::Error for IpcError {}
pub type Result<T> = std::result::Result<T, IpcError>;

pub struct MessageBus {
    subscribers: Arc<Mutex<HashMap<String, Vec<Arc<Mutex<Vec<IpcMessage>>>>>>>,
    msg_counter: Arc<Mutex<u64>>,
}

impl MessageBus {
    pub fn new() -> Self {
        Self {
            subscribers: Arc::new(Mutex::new(HashMap::new())),
            msg_counter: Arc::new(Mutex::new(0)),
        }
    }

    pub fn subscribe(&self, topic: &str) -> Result<Arc<Mutex<Vec<IpcMessage>>>> {
        let inbox = Arc::new(Mutex::new(Vec::new()));
        let mut subs = self.subscribers.lock().map_err(|e| IpcError::LockPoisoned(e.to_string()))?;
        subs.entry(topic.to_string()).or_default().push(Arc::clone(&inbox));
        Ok(inbox)
    }

    pub fn publish(&self, topic: &str, payload: Vec<u8>, priority: u8) -> Result<u64> {
        let mut counter = self.msg_counter.lock().map_err(|e| IpcError::LockPoisoned(e.to_string()))?;
        *counter += 1;
        let msg = IpcMessage {
            id: *counter, channel: topic.to_string(), payload, priority,
            timestamp_ns: std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).expect("[TSM.ID]").as_nanos() as u64,
        };
        let subs = self.subscribers.lock().map_err(|e| IpcError::LockPoisoned(e.to_string()))?;
        if let Some(inboxes) = subs.get(topic) {
            for inbox in inboxes {
                if let Ok(mut q) = inbox.lock() { q.push(msg.clone()); }
            }
        }
        Ok(msg.id)
    }
}

impl Default for MessageBus {
    fn default() -> Self { Self::new() }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_pubsub() {
        let bus = MessageBus::new();
        let inbox = bus.subscribe("test").unwrap();
        bus.publish("test", vec![1,2,3], 5).unwrap();
        let msgs = inbox.lock().unwrap();
        assert_eq!(msgs.len(), 1);
        assert_eq!(msgs[0].payload, vec![1,2,3]);
    }
}
