//! Event bus for bidirectional ecosystem communication

use serde::{Deserialize, Serialize};
use std::sync::Arc;
use tokio::sync::broadcast;
use tracing::{debug, info};

/// Event emitted by Syntaxis to ecosystem
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum EcosystemEvent {
    /// Task created in Syntaxis
    TaskCreated {
        task_id: String,
        description: String,
        phase: String,
    },

    /// Task state changed
    TaskStateChanged {
        task_id: String,
        old_state: String,
        new_state: String,
    },

    /// Task completed
    TaskCompleted { task_id: String },

    /// Task blocked
    TaskBlocked { task_id: String, reason: String },

    /// Phase transitioning
    PhaseTransitioning {
        from: String,
        to: String,
        timestamp: String,
    },

    /// Phase transitioned
    PhaseTransitioned {
        from: String,
        to: String,
        timestamp: String,
    },

    /// Task action execution requested
    ExecuteAction {
        task_id: String,
        action_type: String,
        config: serde_json::Value,
    },

    /// Custom integration event
    Custom {
        event_type: String,
        data: serde_json::Value,
    },
}

impl EcosystemEvent {
    /// Get event type name
    pub fn event_type(&self) -> &str {
        match self {
            Self::TaskCreated { .. } => "task_created",
            Self::TaskStateChanged { .. } => "task_state_changed",
            Self::TaskCompleted { .. } => "task_completed",
            Self::TaskBlocked { .. } => "task_blocked",
            Self::PhaseTransitioning { .. } => "phase_transitioning",
            Self::PhaseTransitioned { .. } => "phase_transitioned",
            Self::ExecuteAction { .. } => "execute_action",
            Self::Custom { event_type, .. } => event_type,
        }
    }
}

/// Event bus for distributing ecosystem events
#[derive(Clone)]
pub struct EventBus {
    tx: broadcast::Sender<EcosystemEvent>,
}

impl EventBus {
    /// Create a new event bus
    pub fn new() -> Self {
        let (tx, _) = broadcast::channel(100);
        Self { tx }
    }

    /// Create a new event bus with custom capacity
    pub fn with_capacity(capacity: usize) -> Self {
        let (tx, _) = broadcast::channel(capacity);
        Self { tx }
    }

    /// Publish an event
    pub fn publish(
        &self,
        event: EcosystemEvent,
    ) -> Result<usize, broadcast::error::SendError<EcosystemEvent>> {
        info!("Publishing ecosystem event: {}", event.event_type());
        debug!("Event details: {:?}", event);
        self.tx.send(event)
    }

    /// Subscribe to events
    pub fn subscribe(&self) -> broadcast::Receiver<EcosystemEvent> {
        self.tx.subscribe()
    }

    /// Get number of active subscribers
    pub fn subscriber_count(&self) -> usize {
        self.tx.receiver_count()
    }

    /// Check if anyone is listening
    pub fn has_subscribers(&self) -> bool {
        self.subscriber_count() > 0
    }
}

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

/// Event handler function type
pub type EventHandler = Arc<dyn Fn(EcosystemEvent) + Send + Sync>;

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

    #[test]
    fn test_event_type_name() {
        let event = EcosystemEvent::TaskCreated {
            task_id: "123".to_string(),
            description: "Test".to_string(),
            phase: "devel".to_string(),
        };
        assert_eq!(event.event_type(), "task_created");
    }

    #[test]
    fn test_event_bus_creation() {
        let bus = EventBus::new();
        assert_eq!(bus.subscriber_count(), 0);
    }

    #[tokio::test]
    async fn test_event_bus_publish_subscribe() {
        let bus = EventBus::new();
        let mut rx = bus.subscribe();

        let event = EcosystemEvent::TaskCreated {
            task_id: "test-123".to_string(),
            description: "Test task".to_string(),
            phase: "devel".to_string(),
        };

        assert!(bus.publish(event.clone()).is_ok());

        let received = rx.recv().await.unwrap();
        match received {
            EcosystemEvent::TaskCreated { task_id, .. } => {
                assert_eq!(task_id, "test-123");
            }
            _ => panic!("Expected TaskCreated event"),
        }
    }

    #[tokio::test]
    async fn test_multiple_subscribers() {
        let bus = EventBus::new();
        let mut rx1 = bus.subscribe();
        let mut rx2 = bus.subscribe();

        let event = EcosystemEvent::TaskCompleted {
            task_id: "test".to_string(),
        };

        let result = bus.publish(event);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), 2); // 2 subscribers

        let _ = rx1.recv().await;
        let _ = rx2.recv().await;
    }

    #[test]
    fn test_custom_event() {
        let event = EcosystemEvent::Custom {
            event_type: "my_custom_event".to_string(),
            data: serde_json::json!({"key": "value"}),
        };

        assert_eq!(event.event_type(), "my_custom_event");
    }
}
