//! Node factory for dynamic node creation.

use crate::runtime::{add_node_handler, MessageHandler, NodeBase, Result, RobomotionError};
use async_trait::async_trait;
use parking_lot::RwLock;
use std::collections::HashMap;

/// Factory trait for creating nodes.
#[async_trait]
pub trait NodeFactory: Send + Sync + 'static {
    /// Create a new node instance from configuration.
    async fn on_create(&self, config: &[u8]) -> Result<()>;
}

// Global factories registry
lazy_static::lazy_static! {
    static ref FACTORIES: RwLock<HashMap<String, Box<dyn NodeFactory>>> = RwLock::new(HashMap::new());
}

/// Register a node factory.
pub fn register_node_factory(name: &str, factory: Box<dyn NodeFactory>) {
    FACTORIES.write().insert(name.to_string(), factory);
}

/// Get a node factory by name.
pub fn get_node_factory(name: &str) -> Option<Box<dyn NodeFactory>> {
    // We can't actually return owned Box, so we'll need a different approach
    None
}

/// Check if a factory exists for the given name.
pub fn has_node_factory(name: &str) -> bool {
    FACTORIES.read().contains_key(name)
}

/// Create a node using the registered factory.
pub async fn create_node(name: &str, config: &[u8]) -> Result<()> {
    let factories = FACTORIES.read();
    let factory = factories
        .get(name)
        .ok_or_else(|| RobomotionError::FactoryNotFound(name.to_string()))?;
    factory.on_create(config).await
}

/// Generic node factory implementation.
pub struct GenericNodeFactory<F>
where
    F: Fn() -> Box<dyn MessageHandler> + Send + Sync + 'static,
{
    creator: F,
}

impl<F> GenericNodeFactory<F>
where
    F: Fn() -> Box<dyn MessageHandler> + Send + Sync + 'static,
{
    pub fn new(creator: F) -> Self {
        Self { creator }
    }
}

#[async_trait]
impl<F> NodeFactory for GenericNodeFactory<F>
where
    F: Fn() -> Box<dyn MessageHandler> + Send + Sync + 'static,
{
    async fn on_create(&self, config: &[u8]) -> Result<()> {
        // Parse the config to get node base properties
        let node_base: NodeBase = serde_json::from_slice(config)?;

        // Create the handler
        let mut handler = (self.creator)();

        // The handler needs to be deserialized from config too
        // This is a simplified version - the actual implementation would
        // need to handle this more carefully

        add_node_handler(node_base, handler);
        Ok(())
    }
}
