//! Event streaming for real-time syntaxis updates
//!
//! Provides WebSocket-based event streaming for real-time synchronization.

use serde::{Deserialize, Serialize};

/// Lifecycle events
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum LifecycleEvent {
    /// Project created
    ProjectCreated {
        /// Project ID
        project_id: String,
        /// Project name
        name: String,
    },
    /// Phase transitioned
    PhaseTransitioned {
        /// Project ID
        project_id: String,
        /// From phase
        from_phase: String,
        /// To phase
        to_phase: String,
    },
    /// Checklist item completed
    ChecklistItemCompleted {
        /// Project ID
        project_id: String,
        /// Item ID
        item_id: String,
        /// Item title
        title: String,
    },
    /// Security assessment updated
    SecurityUpdated {
        /// Project ID
        project_id: String,
        /// Risk level
        risk_level: String,
    },
    /// Tool enabled/disabled
    ToolToggled {
        /// Project ID
        project_id: String,
        /// Tool name
        tool_name: String,
        /// Enabled state
        enabled: bool,
    },
}

impl LifecycleEvent {
    /// Get event type name
    pub fn event_type(&self) -> &'static str {
        match self {
            Self::ProjectCreated { .. } => "project_created",
            Self::PhaseTransitioned { .. } => "phase_transitioned",
            Self::ChecklistItemCompleted { .. } => "checklist_item_completed",
            Self::SecurityUpdated { .. } => "security_updated",
            Self::ToolToggled { .. } => "tool_toggled",
        }
    }

    /// Get timestamp
    pub fn timestamp(&self) -> String {
        chrono::Local::now().to_rfc3339()
    }
}

/// Event stream subscription
#[derive(Debug, Clone)]
pub struct EventSubscription {
    /// Channel name for subscription
    channel_name: String,
}

impl EventSubscription {
    /// Create new subscription
    pub fn new(channel: impl Into<String>) -> Self {
        Self {
            channel_name: channel.into(),
        }
    }

    /// Get subscription channel
    pub fn channel(&self) -> &str {
        &self.channel_name
    }
}

/// Event stream manager
#[derive(Debug, Clone)]
pub struct EventStream {
    /// API URL for event streaming
    #[allow(dead_code)]
    api_url: String,
}

impl EventStream {
    /// Create new event stream
    pub fn new(api_url: impl Into<String>) -> Self {
        Self {
            api_url: api_url.into(),
        }
    }

    /// Subscribe to events
    pub async fn subscribe(&self, project_id: &str) -> anyhow::Result<EventSubscription> {
        // In production, establish WebSocket connection
        // and subscribe to project-specific events
        Ok(EventSubscription::new(format!("project:{}", project_id)))
    }

    /// Publish event
    pub async fn publish(&self, event: &LifecycleEvent) -> anyhow::Result<()> {
        // In production, send event to WebSocket server
        tracing::info!(
            event_type = event.event_type(),
            timestamp = event.timestamp(),
            "Event published"
        );
        Ok(())
    }

    /// Subscribe to all events
    pub async fn subscribe_all(&self) -> anyhow::Result<EventSubscription> {
        Ok(EventSubscription::new("lifecycle:*"))
    }

    /// Listen for events (returns next event or timeout)
    pub async fn listen(
        &self,
        _subscription: &EventSubscription,
    ) -> anyhow::Result<LifecycleEvent> {
        // In production, wait for next event from WebSocket
        Err(anyhow::anyhow!("No events available"))
    }
}

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

    #[test]
    fn test_event_type_names() {
        let event = LifecycleEvent::ProjectCreated {
            project_id: "proj1".to_string(),
            name: "Test".to_string(),
        };
        assert_eq!(event.event_type(), "project_created");
    }

    #[test]
    fn test_event_creation() {
        let event = LifecycleEvent::PhaseTransitioned {
            project_id: "proj1".to_string(),
            from_phase: "planning".to_string(),
            to_phase: "design".to_string(),
        };

        assert_eq!(event.event_type(), "phase_transitioned");
        assert!(!event.timestamp().is_empty());
    }

    #[test]
    fn test_event_subscription() {
        let sub = EventSubscription::new("project:123");
        assert_eq!(sub.channel(), "project:123");
    }

    #[test]
    fn test_event_stream_creation() {
        let stream = EventStream::new("ws://localhost:7000");
        assert!(!stream.api_url.is_empty());
    }

    #[tokio::test]
    async fn test_publish_event() {
        let stream = EventStream::new("ws://localhost:7000");
        let event = LifecycleEvent::ProjectCreated {
            project_id: "proj1".to_string(),
            name: "Test".to_string(),
        };
        let result = stream.publish(&event).await;
        assert!(result.is_ok());
    }

    #[tokio::test]
    async fn test_subscribe() {
        let stream = EventStream::new("ws://localhost:7000");
        let sub = stream.subscribe("proj1").await;
        assert!(sub.is_ok());
    }
}
