coderlib 0.1.0

A Rust library for AI-powered code assistance and agentic system
Documentation
//! Event handling utilities for CoderLib integration
//!
//! This module provides event handling and communication utilities for
//! integrating CoderLib with host applications.

use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::{broadcast, mpsc};

use crate::integration::{CoderEvent, HostEvent, HostCommand};
use crate::core::error::IntegrationError;

/// Event bus for communication between CoderLib and host applications
pub struct EventBus {
    /// Sender for CoderLib events
    coder_event_tx: broadcast::Sender<CoderEvent>,
    
    /// Sender for host events
    host_event_tx: broadcast::Sender<HostEvent>,
    
    /// Sender for host commands
    host_command_tx: mpsc::Sender<HostCommand>,
    
    /// Event handlers
    handlers: HashMap<String, Box<dyn EventHandler>>,
}

/// Trait for handling events
pub trait EventHandler: Send + Sync {
    /// Handle a CoderLib event
    fn handle_coder_event(&self, event: &CoderEvent) -> Result<Option<HostCommand>, IntegrationError>;
    
    /// Handle a host event
    fn handle_host_event(&self, event: &HostEvent) -> Result<Option<CoderEvent>, IntegrationError>;
}

impl EventBus {
    /// Create a new event bus
    pub fn new() -> Self {
        let (coder_event_tx, _) = broadcast::channel(1000);
        let (host_event_tx, _) = broadcast::channel(1000);
        let (host_command_tx, _) = mpsc::channel(100);
        
        Self {
            coder_event_tx,
            host_event_tx,
            host_command_tx,
            handlers: HashMap::new(),
        }
    }
    
    /// Register an event handler
    pub fn register_handler(&mut self, name: String, handler: Box<dyn EventHandler>) {
        self.handlers.insert(name, handler);
    }
    
    /// Send a CoderLib event
    pub fn send_coder_event(&self, event: CoderEvent) -> Result<(), IntegrationError> {
        self.coder_event_tx.send(event)
            .map_err(|e| IntegrationError::Communication(e.to_string()))?;
        Ok(())
    }
    
    /// Send a host event
    pub fn send_host_event(&self, event: HostEvent) -> Result<(), IntegrationError> {
        self.host_event_tx.send(event)
            .map_err(|e| IntegrationError::Communication(e.to_string()))?;
        Ok(())
    }
    
    /// Send a host command
    pub async fn send_host_command(&self, command: HostCommand) -> Result<(), IntegrationError> {
        self.host_command_tx.send(command).await
            .map_err(|e| IntegrationError::Communication(e.to_string()))?;
        Ok(())
    }
    
    /// Subscribe to CoderLib events
    pub fn subscribe_coder_events(&self) -> broadcast::Receiver<CoderEvent> {
        self.coder_event_tx.subscribe()
    }
    
    /// Subscribe to host events
    pub fn subscribe_host_events(&self) -> broadcast::Receiver<HostEvent> {
        self.host_event_tx.subscribe()
    }
    
    /// Get host command receiver
    pub fn get_host_command_receiver(&mut self) -> mpsc::Receiver<HostCommand> {
        let (tx, rx) = mpsc::channel(100);
        self.host_command_tx = tx;
        rx
    }
    
    /// Start the event processing loop
    pub async fn run(&self) -> Result<(), IntegrationError> {
        let mut coder_rx = self.subscribe_coder_events();
        let mut host_rx = self.subscribe_host_events();
        
        loop {
            tokio::select! {
                Ok(coder_event) = coder_rx.recv() => {
                    self.process_coder_event(&coder_event).await?;
                }
                Ok(host_event) = host_rx.recv() => {
                    self.process_host_event(&host_event).await?;
                }
                else => break,
            }
        }
        
        Ok(())
    }
    
    /// Process a CoderLib event
    async fn process_coder_event(&self, event: &CoderEvent) -> Result<(), IntegrationError> {
        for handler in self.handlers.values() {
            if let Some(command) = handler.handle_coder_event(event)? {
                self.send_host_command(command).await?;
            }
        }
        Ok(())
    }
    
    /// Process a host event
    async fn process_host_event(&self, event: &HostEvent) -> Result<(), IntegrationError> {
        for handler in self.handlers.values() {
            if let Some(coder_event) = handler.handle_host_event(event)? {
                self.send_coder_event(coder_event)?;
            }
        }
        Ok(())
    }
}

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

/// Event bridge for connecting CoderLib with host applications
pub struct EventBridge {
    event_bus: Arc<EventBus>,
}

impl EventBridge {
    /// Create a new event bridge
    pub fn new(event_bus: Arc<EventBus>) -> Self {
        Self { event_bus }
    }
    
    /// Forward CoderLib events to the host
    pub async fn forward_coder_events(&self) -> Result<(), IntegrationError> {
        let mut rx = self.event_bus.subscribe_coder_events();
        
        while let Ok(event) = rx.recv().await {
            // Forward event to host application
            // This would be implemented based on the specific host integration
            tracing::debug!("Forwarding CoderLib event: {:?}", event);
        }
        
        Ok(())
    }
    
    /// Forward host events to CoderLib
    pub async fn forward_host_events(&self) -> Result<(), IntegrationError> {
        let mut rx = self.event_bus.subscribe_host_events();
        
        while let Ok(event) = rx.recv().await {
            // Forward event to CoderLib
            // This would be implemented based on the specific CoderLib integration
            tracing::debug!("Forwarding host event: {:?}", event);
        }
        
        Ok(())
    }
}

/// Default event handler for basic functionality
pub struct DefaultEventHandler;

impl EventHandler for DefaultEventHandler {
    fn handle_coder_event(&self, event: &CoderEvent) -> Result<Option<HostCommand>, IntegrationError> {
        match event {
            CoderEvent::ProcessingStarted { session_id } => {
                Ok(Some(HostCommand::ShowMessage {
                    message: format!("AI processing started for session {}", session_id),
                    level: crate::integration::MessageLevel::Info,
                }))
            }
            CoderEvent::ProcessingCompleted { session_id, response } => {
                Ok(Some(HostCommand::ShowMessage {
                    message: format!("AI processing completed for session {}: {}", session_id, response),
                    level: crate::integration::MessageLevel::Success,
                }))
            }
            CoderEvent::ProcessingFailed { session_id, error } => {
                Ok(Some(HostCommand::ShowMessage {
                    message: format!("AI processing failed for session {}: {}", session_id, error),
                    level: crate::integration::MessageLevel::Error,
                }))
            }
            CoderEvent::StatusUpdate { message } => {
                Ok(Some(HostCommand::ShowMessage {
                    message: message.clone(),
                    level: crate::integration::MessageLevel::Info,
                }))
            }
            _ => Ok(None),
        }
    }
    
    fn handle_host_event(&self, event: &HostEvent) -> Result<Option<CoderEvent>, IntegrationError> {
        match event {
            HostEvent::FileOpened(path) => {
                Ok(Some(CoderEvent::StatusUpdate {
                    message: format!("File opened: {}", path.display()),
                }))
            }
            HostEvent::FileSaved(path) => {
                Ok(Some(CoderEvent::StatusUpdate {
                    message: format!("File saved: {}", path.display()),
                }))
            }
            HostEvent::ProjectOpened(path) => {
                Ok(Some(CoderEvent::StatusUpdate {
                    message: format!("Project opened: {}", path.display()),
                }))
            }
            _ => Ok(None),
        }
    }
}

/// Event filter for filtering events based on criteria
pub struct EventFilter<F> {
    filter_fn: F,
}

impl<F> EventFilter<F>
where
    F: Fn(&CoderEvent) -> bool + Send + Sync,
{
    pub fn new(filter_fn: F) -> Self {
        Self { filter_fn }
    }
}

impl<F> EventHandler for EventFilter<F>
where
    F: Fn(&CoderEvent) -> bool + Send + Sync,
{
    fn handle_coder_event(&self, event: &CoderEvent) -> Result<Option<HostCommand>, IntegrationError> {
        if (self.filter_fn)(event) {
            // Event passed the filter, could forward it or take action
            Ok(None)
        } else {
            // Event filtered out
            Ok(None)
        }
    }
    
    fn handle_host_event(&self, _event: &HostEvent) -> Result<Option<CoderEvent>, IntegrationError> {
        Ok(None)
    }
}

/// Event logger for debugging and monitoring
pub struct EventLogger {
    log_coder_events: bool,
    log_host_events: bool,
}

impl EventLogger {
    pub fn new(log_coder_events: bool, log_host_events: bool) -> Self {
        Self {
            log_coder_events,
            log_host_events,
        }
    }
}

impl EventHandler for EventLogger {
    fn handle_coder_event(&self, event: &CoderEvent) -> Result<Option<HostCommand>, IntegrationError> {
        if self.log_coder_events {
            tracing::info!("CoderLib event: {:?}", event);
        }
        Ok(None)
    }
    
    fn handle_host_event(&self, event: &HostEvent) -> Result<Option<CoderEvent>, IntegrationError> {
        if self.log_host_events {
            tracing::info!("Host event: {:?}", event);
        }
        Ok(None)
    }
}

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

    #[tokio::test]
    async fn test_event_bus_creation() {
        let event_bus = EventBus::new();
        assert_eq!(event_bus.handlers.len(), 0);
    }

    #[tokio::test]
    async fn test_event_sending() {
        let event_bus = EventBus::new();

        // Create receivers to prevent send errors
        let _coder_rx = event_bus.subscribe_coder_events();
        let _host_rx = event_bus.subscribe_host_events();

        let coder_event = CoderEvent::ProcessingStarted {
            session_id: "test".to_string(),
        };

        let result = event_bus.send_coder_event(coder_event);
        assert!(result.is_ok());

        let host_event = HostEvent::FileOpened(PathBuf::from("test.txt"));
        let result = event_bus.send_host_event(host_event);
        assert!(result.is_ok());
    }

    #[test]
    fn test_default_event_handler() {
        let handler = DefaultEventHandler;
        
        let event = CoderEvent::ProcessingStarted {
            session_id: "test".to_string(),
        };
        
        let result = handler.handle_coder_event(&event);
        assert!(result.is_ok());
        assert!(result.unwrap().is_some());
    }

    #[test]
    fn test_event_filter() {
        let filter = EventFilter::new(|event| {
            matches!(event, CoderEvent::ProcessingStarted { .. })
        });
        
        let start_event = CoderEvent::ProcessingStarted {
            session_id: "test".to_string(),
        };
        
        let complete_event = CoderEvent::ProcessingCompleted {
            session_id: "test".to_string(),
            response: "done".to_string(),
        };
        
        let result1 = filter.handle_coder_event(&start_event);
        assert!(result1.is_ok());
        
        let result2 = filter.handle_coder_event(&complete_event);
        assert!(result2.is_ok());
    }
}