#![deny(warnings)]
#![allow(dead_code)]
//! [TSM.ID].[11031972] -- Platform X Ecosystem
//! xcu-command-center -- Central Command Dispatcher & Router
use std::collections::HashMap;

#[derive(Debug)]
pub enum CmdError {
    NotFound(String),
    ExecFailed(String),
    InvalidPayload(String),
}
impl std::fmt::Display for CmdError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::NotFound(e) | Self::ExecFailed(e) | Self::InvalidPayload(e) => write!(f, "{e}"),
        }
    }
}
impl std::error::Error for CmdError {}

#[derive(Debug, Clone, PartialEq)]
pub enum CommandType { Execute, Query, Subscribe, Unsubscribe, Broadcast }

#[derive(Debug, Clone)]
pub struct Command {
    pub id: u64,
    pub cmd_type: CommandType,
    pub target: String,
    pub payload: Vec<u8>,
    pub priority: u8,
}

#[derive(Debug, Clone)]
pub struct CommandResult {
    pub cmd_id: u64,
    pub success: bool,
    pub data: Vec<u8>,
}

pub struct CommandCenter {
    handlers: HashMap<String, Box<dyn Fn(&Command) -> Result<CommandResult, CmdError> + Send>>,
    history: Vec<(u64, bool)>,
    next_id: u64,
}

impl CommandCenter {
    pub fn new() -> Self {
        Self { handlers: HashMap::new(), history: Vec::new(), next_id: 1 }
    }

    pub fn register<F>(&mut self, target: &str, handler: F)
    where F: Fn(&Command) -> Result<CommandResult, CmdError> + Send + 'static {
        self.handlers.insert(target.to_string(), Box::new(handler));
    }

    pub fn dispatch(&mut self, cmd: &Command) -> Result<CommandResult, CmdError> {
        let handler = self.handlers.get(&cmd.target)
            .ok_or_else(|| CmdError::NotFound(format!("No handler for '{}'", cmd.target)))?;
        let result = handler(cmd)?;
        self.history.push((cmd.id, result.success));
        Ok(result)
    }

    pub fn create_command(&mut self, cmd_type: CommandType, target: &str, payload: Vec<u8>, priority: u8) -> Command {
        let id = self.next_id;
        self.next_id += 1;
        Command { id, cmd_type, target: target.to_string(), payload, priority }
    }

    pub fn history_count(&self) -> usize { self.history.len() }
    pub fn success_rate(&self) -> f64 {
        if self.history.is_empty() { return 0.0; }
        let ok = self.history.iter().filter(|(_, s)| *s).count();
        ok as f64 / self.history.len() as f64
    }
    pub fn handler_count(&self) -> usize { self.handlers.len() }
}

pub struct PriorityQueue {
    items: Vec<Command>,
}
impl PriorityQueue {
    pub fn new() -> Self { Self { items: Vec::new() } }
    pub fn push(&mut self, cmd: Command) {
        let pos = self.items.iter().position(|c| c.priority < cmd.priority).unwrap_or(self.items.len());
        self.items.insert(pos, cmd);
    }
    pub fn pop(&mut self) -> Option<Command> {
        if self.items.is_empty() { None } else { Some(self.items.remove(0)) }
    }
    pub fn len(&self) -> usize { self.items.len() }
    pub fn is_empty(&self) -> bool { self.items.is_empty() }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_dispatch_and_history() {
        let mut cc = CommandCenter::new();
        cc.register("echo", |cmd| Ok(CommandResult {
            cmd_id: cmd.id, success: true, data: cmd.payload.clone(),
        }));
        let cmd = cc.create_command(CommandType::Execute, "echo", vec![1, 2, 3], 5);
        let result = cc.dispatch(&cmd).unwrap();
        assert!(result.success);
        assert_eq!(result.data, vec![1, 2, 3]);
        assert_eq!(cc.history_count(), 1);
        assert!((cc.success_rate() - 1.0).abs() < 1e-10);
    }

    #[test]
    fn test_not_found() {
        let mut cc = CommandCenter::new();
        let cmd = cc.create_command(CommandType::Query, "missing", vec![], 1);
        assert!(cc.dispatch(&cmd).is_err());
    }

    #[test]
    fn test_priority_queue() {
        let mut pq = PriorityQueue::new();
        pq.push(Command { id: 1, cmd_type: CommandType::Execute, target: "a".into(), payload: vec![], priority: 1 });
        pq.push(Command { id: 2, cmd_type: CommandType::Execute, target: "b".into(), payload: vec![], priority: 10 });
        pq.push(Command { id: 3, cmd_type: CommandType::Execute, target: "c".into(), payload: vec![], priority: 5 });
        assert_eq!(pq.len(), 3);
        assert_eq!(pq.pop().unwrap().id, 2); // highest priority first
        assert_eq!(pq.pop().unwrap().id, 3);
        assert_eq!(pq.pop().unwrap().id, 1);
    }
}
