//! Actor observatory for live system introspection (RUCHY-0817)
//!
//! Provides comprehensive monitoring and debugging capabilities for the actor system,
//! including message tracing, deadlock detection, and performance analysis.
#[cfg(test)]
mod tests {
    use super::*;
    use crate::runtime::actor::{ActorSystem, Message};
    use std::sync::{Arc, Mutex};
    use std::time::Duration;
    // Helper functions for consistent test setup
    fn create_test_actor_system() -> Arc<Mutex<ActorSystem>> {
        ActorSystem::new()
    }
    fn create_test_config() -> ObservatoryConfig {
        ObservatoryConfig {
            max_traces: 100,
            trace_retention_seconds: 3600,
            enable_deadlock_detection: true,
            deadlock_check_interval_ms: 1000,
            enable_metrics: true,
            metrics_interval_ms: 5000,
            max_snapshots: 50,
        }
    }
    fn create_test_observatory() -> ActorObservatory {
        let system = create_test_actor_system();
        let config = create_test_config();
        ActorObservatory::new(system, config)
    }
    fn create_test_message_trace() -> MessageTrace {
        MessageTrace {
            trace_id: 12345,
            timestamp: current_timestamp(),
            source: Some(ActorId(1)),
            destination: ActorId(2),
            message: Message::User("test_message".to_string(), vec![]),
            status: MessageStatus::Queued,
            processing_duration_us: None,
            error: None,
            stack_depth: 1,
            correlation_id: Some("corr-123".to_string()),
        }
    }
    fn create_test_actor_snapshot() -> ActorSnapshot {
        ActorSnapshot {
            actor_id: ActorId(1),
            name: "test_actor".to_string(),
            timestamp: current_timestamp(),
            state: ActorState::Running,
            mailbox_size: 5,
            parent: Some(ActorId(0)),
            children: vec![ActorId(2), ActorId(3)],
            message_stats: MessageStats::default(),
            memory_usage: Some(1024),
        }
    }
    fn create_test_message_filter() -> MessageFilter {
        MessageFilter {
            name: "test_filter".to_string(),
            actor_id: Some(ActorId(1)),
            actor_name_pattern: Some("test_actor".to_string()),
            message_type_pattern: Some(".*message.*".to_string()),
            min_processing_time_us: None,
            failed_only: false,
            max_stack_depth: Some(10),
        }
    }
    // ========== Observatory Configuration Tests ==========
    #[test]
    fn test_observatory_config_default() {
        let config = ObservatoryConfig::default();
        assert_eq!(config.max_traces, 10000);
        assert_eq!(config.trace_retention_seconds, 3600);
        assert!(config.enable_deadlock_detection);
        assert_eq!(config.deadlock_check_interval_ms, 1000);
        assert!(config.enable_metrics);
        assert_eq!(config.metrics_interval_ms, 5000);
        assert_eq!(config.max_snapshots, 1000);
    }
    #[test]
    fn test_observatory_config_clone() {
        let config1 = create_test_config();
        let config2 = config1.clone();
        assert_eq!(config1.max_traces, config2.max_traces);
        assert_eq!(
            config1.enable_deadlock_detection,
            config2.enable_deadlock_detection
        );
    }
    #[test]
    fn test_observatory_config_debug() {
        let config = create_test_config();
        let debug_str = format!("{config:?}");
        assert!(debug_str.contains("ObservatoryConfig"));
        assert!(debug_str.contains("max_traces"));
        assert!(debug_str.contains("enable_deadlock_detection"));
    }
    #[test]
    fn test_observatory_config_serialization() {
        let config = create_test_config();
        let json = serde_json::to_string(&config).unwrap();
        let deserialized: ObservatoryConfig = serde_json::from_str(&json).unwrap();
        assert_eq!(config.max_traces, deserialized.max_traces);
        assert_eq!(config.enable_metrics, deserialized.enable_metrics);
    }
    // ========== Observatory Creation and Setup Tests ==========
    #[test]
    fn test_observatory_creation() {
        let system = create_test_actor_system();
        let config = create_test_config();
        let observatory = ActorObservatory::new(system, config.clone());
        assert_eq!(observatory.config.max_traces, config.max_traces);
        assert!(observatory.filters.is_empty());
        assert!(observatory.start_time.elapsed() < Duration::from_secs(1));
    }
    #[test]
    fn test_observatory_with_default_config() {
        let system = create_test_actor_system();
        let config = ObservatoryConfig::default();
        let observatory = ActorObservatory::new(system, config);
        assert_eq!(observatory.config.max_traces, 10000);
        assert!(observatory.config.enable_deadlock_detection);
    }
    #[test]
    fn test_observatory_initialization_state() {
        let observatory = create_test_observatory();
        // Should start with empty state
        assert!(observatory.get_filters().is_empty());
        let metrics = observatory.metrics.lock().expect("Failed to acquire lock");
        assert_eq!(metrics.active_actors, 0);
        assert_eq!(metrics.total_messages_processed, 0);
    }
    // ========== Message Filter Management Tests ==========
    #[test]
    fn test_add_message_filter() {
        let mut observatory = create_test_observatory();
        let filter = create_test_message_filter();
        observatory.add_filter(filter.clone());
        assert_eq!(observatory.get_filters().len(), 1);
        assert_eq!(observatory.get_filters()[0].name, filter.name);
    }
    #[test]
    fn test_add_multiple_filters() {
        let mut observatory = create_test_observatory();
        let filter1 = MessageFilter {
            name: "filter1".to_string(),
            actor_id: None,
            actor_name_pattern: None,
            message_type_pattern: Some("type1".to_string()),
            min_processing_time_us: None,
            failed_only: false,
            max_stack_depth: None,
        };
        let filter2 = MessageFilter {
            name: "filter2".to_string(),
            actor_id: Some(ActorId(2)),
            actor_name_pattern: Some("actor2".to_string()),
            message_type_pattern: None,
            min_processing_time_us: Some(1000),
            failed_only: true,
            max_stack_depth: Some(5),
        };
        observatory.add_filter(filter1);
        observatory.add_filter(filter2);
        assert_eq!(observatory.get_filters().len(), 2);
        assert_eq!(observatory.get_filters()[0].name, "filter1");
        assert_eq!(observatory.get_filters()[1].name, "filter2");
    }
    #[test]
    fn test_remove_message_filter() {
        let mut observatory = create_test_observatory();
        let filter = create_test_message_filter();
        observatory.add_filter(filter);
        assert_eq!(observatory.get_filters().len(), 1);
        let removed = observatory.remove_filter("test_filter");
        assert!(removed);
        assert!(observatory.get_filters().is_empty());
    }
    #[test]
    fn test_remove_nonexistent_filter() {
        let mut observatory = create_test_observatory();
        let removed = observatory.remove_filter("nonexistent");
        assert!(!removed);
    }
    #[test]
    fn test_get_filters_empty() {
        let observatory = create_test_observatory();
        assert!(observatory.get_filters().is_empty());
    }
    // ========== Message Tracing Tests ==========
    #[test]
    fn test_trace_message() {
        let observatory = create_test_observatory();
        let trace = create_test_message_trace();
        let result = observatory.trace_message(trace.clone());
        assert!(result.is_ok());
        let traces = observatory.get_traces(None, None).unwrap();
        assert_eq!(traces.len(), 1);
        assert_eq!(traces[0].trace_id, trace.trace_id);
    }
    #[test]
    fn test_trace_message_with_limit() {
        let mut observatory = create_test_observatory();
        observatory.config.max_traces = 2;
        // Add 3 traces, should only keep 2 most recent
        for i in 0..3 {
            let mut trace = create_test_message_trace();
            trace.trace_id = i as u64;
            observatory.trace_message(trace).unwrap();
        }
        let traces = observatory.get_traces(None, None).unwrap();
        assert_eq!(traces.len(), 2);
        assert_eq!(traces[0].trace_id, 1); // First trace should be evicted
        assert_eq!(traces[1].trace_id, 2);
    }
    #[test]
    fn test_trace_message_age_retention() {
        let mut observatory = create_test_observatory();
        observatory.config.trace_retention_seconds = 1; // 1 second retention
                                                        // Add an old trace
        let mut old_trace = create_test_message_trace();
        old_trace.timestamp = current_timestamp() - 3600; // 1 hour ago
        observatory.trace_message(old_trace).unwrap();
        // Add a recent trace
        let recent_trace = create_test_message_trace();
        observatory.trace_message(recent_trace).unwrap();
        let traces = observatory.get_traces(None, None).unwrap();
        // Only recent trace should remain
        assert_eq!(traces.len(), 1);
    }
    #[test]
    fn test_get_traces_with_limit() {
        let observatory = create_test_observatory();
        // Add 5 traces
        for i in 0..5 {
            let mut trace = create_test_message_trace();
            trace.trace_id = i as u64;
            observatory.trace_message(trace).unwrap();
        }
        let traces = observatory.get_traces(Some(3), None).unwrap();
        assert_eq!(traces.len(), 3);
    }
    // ========== Message Status Tests ==========
    #[test]
    fn test_message_status_variants() {
        let statuses = [
            MessageStatus::Queued,
            MessageStatus::Processing,
            MessageStatus::Completed,
            MessageStatus::Failed,
            MessageStatus::Dropped,
        ];
        assert_eq!(statuses.len(), 5);
        assert_eq!(statuses[0], MessageStatus::Queued);
        assert_ne!(statuses[0], MessageStatus::Processing);
    }
    #[test]
    fn test_message_status_serialization() {
        let status = MessageStatus::Processing;
        let json = serde_json::to_string(&status).unwrap();
        let deserialized: MessageStatus = serde_json::from_str(&json).unwrap();
        assert_eq!(status, deserialized);
    }
    #[test]
    fn test_message_status_debug() {
        let status = MessageStatus::Failed;
        let debug_str = format!("{status:?}");
        assert!(debug_str.contains("Failed"));
    }
    // ========== Actor State Tests ==========
    #[test]
    fn test_actor_state_variants() {
        let states = [
            ActorState::Starting,
            ActorState::Running,
            ActorState::Processing("test_message".to_string()),
            ActorState::Restarting,
            ActorState::Stopping,
            ActorState::Stopped,
            ActorState::Failed("test_error".to_string()),
        ];
        assert_eq!(states.len(), 7);
        assert_eq!(states[0], ActorState::Starting);
        assert_ne!(states[0], ActorState::Running);
    }
    #[test]
    fn test_actor_state_processing() {
        let state = ActorState::Processing("handle_request".to_string());
        if let ActorState::Processing(message_type) = state {
            assert_eq!(message_type, "handle_request");
        } else {
            panic!("Expected Processing state");
        }
    }
    #[test]
    fn test_actor_state_failed() {
        let state = ActorState::Failed("connection_timeout".to_string());
        if let ActorState::Failed(reason) = state {
            assert_eq!(reason, "connection_timeout");
        } else {
            panic!("Expected Failed state");
        }
    }
    #[test]
    fn test_actor_state_serialization() {
        let state = ActorState::Processing("test".to_string());
        let json = serde_json::to_string(&state).unwrap();
        let deserialized: ActorState = serde_json::from_str(&json).unwrap();
        assert_eq!(state, deserialized);
    }
    // ========== Message Statistics Tests ==========
    #[test]
    fn test_message_stats_default() {
        let stats = MessageStats::default();
        assert_eq!(stats.total_processed, 0);
        assert_eq!(stats.messages_per_second, 0.0);
        assert_eq!(stats.avg_processing_time_us, 0.0);
        assert_eq!(stats.max_processing_time_us, 0);
        assert_eq!(stats.failed_messages, 0);
        assert!(stats.last_processed.is_none());
    }
    #[test]
    fn test_message_stats_clone() {
        let mut stats1 = MessageStats::default();
        stats1.total_processed = 100;
        stats1.messages_per_second = 10.5;
        let stats2 = stats1.clone();
        assert_eq!(stats1.total_processed, stats2.total_processed);
        assert_eq!(stats1.messages_per_second, stats2.messages_per_second);
    }
    #[test]
    fn test_message_stats_serialization() {
        let mut stats = MessageStats::default();
        stats.total_processed = 500;
        stats.avg_processing_time_us = 1500.0;
        let json = serde_json::to_string(&stats).unwrap();
        let deserialized: MessageStats = serde_json::from_str(&json).unwrap();
        assert_eq!(stats.total_processed, deserialized.total_processed);
    }
    // ========== System Metrics Tests ==========
    #[test]
    fn test_system_metrics_default() {
        let metrics = SystemMetrics::default();
        assert_eq!(metrics.active_actors, 0);
        assert_eq!(metrics.total_messages_processed, 0);
        assert_eq!(metrics.system_messages_per_second, 0.0);
        assert_eq!(metrics.total_memory_usage, 0);
        assert_eq!(metrics.total_queued_messages, 0);
        assert_eq!(metrics.avg_mailbox_size, 0.0);
        assert_eq!(metrics.recent_restarts, 0);
        assert!(metrics.last_updated > 0); // Uses current timestamp
    }
    #[test]
    fn test_system_metrics_update() {
        let mut metrics = SystemMetrics::default();
        metrics.active_actors = 10;
        metrics.total_messages_processed = 1000;
        metrics.system_messages_per_second = 50.5;
        metrics.last_updated = current_timestamp();
        assert_eq!(metrics.active_actors, 10);
        assert_eq!(metrics.total_messages_processed, 1000);
        assert!(metrics.last_updated > 0);
    }
    #[test]
    fn test_system_metrics_serialization() {
        let mut metrics = SystemMetrics::default();
        metrics.active_actors = 5;
        metrics.total_memory_usage = 1_024_000;
        let json = serde_json::to_string(&metrics).unwrap();
        let deserialized: SystemMetrics = serde_json::from_str(&json).unwrap();
        assert_eq!(metrics.active_actors, deserialized.active_actors);
        assert_eq!(metrics.total_memory_usage, deserialized.total_memory_usage);
    }
    // ========== Actor Snapshot Tests ==========
    #[test]
    fn test_actor_snapshot_creation() {
        let snapshot = create_test_actor_snapshot();
        assert_eq!(snapshot.actor_id, ActorId(1));
        assert_eq!(snapshot.name, "test_actor");
        assert_eq!(snapshot.state, ActorState::Running);
        assert_eq!(snapshot.mailbox_size, 5);
        assert_eq!(snapshot.children.len(), 2);
        assert!(snapshot.memory_usage.is_some());
    }
    #[test]
    fn test_actor_snapshot_with_no_parent() {
        let mut snapshot = create_test_actor_snapshot();
        snapshot.parent = None;
        assert!(snapshot.parent.is_none());
        assert_eq!(snapshot.children.len(), 2);
    }
    #[test]
    fn test_actor_snapshot_serialization() {
        let snapshot = create_test_actor_snapshot();
        let json = serde_json::to_string(&snapshot).unwrap();
        let deserialized: ActorSnapshot = serde_json::from_str(&json).unwrap();
        assert_eq!(snapshot.actor_id, deserialized.actor_id);
        assert_eq!(snapshot.name, deserialized.name);
        assert_eq!(snapshot.state, deserialized.state);
    }
    // ========== Message Filter Tests ==========
    #[test]
    fn test_message_filter_creation() {
        let filter = create_test_message_filter();
        assert_eq!(filter.name, "test_filter");
        assert!(filter.actor_id.is_some());
        assert!(filter.actor_name_pattern.is_some());
        assert!(filter.message_type_pattern.is_some());
        assert!(!filter.failed_only);
    }
    #[test]
    fn test_message_filter_with_duration_limits() {
        let filter = MessageFilter {
            name: "duration_filter".to_string(),
            actor_id: None,
            actor_name_pattern: None,
            message_type_pattern: None,
            min_processing_time_us: Some(1000),
            failed_only: false,
            max_stack_depth: None,
        };
        assert_eq!(filter.min_processing_time_us, Some(1000));
    }
    #[test]
    fn test_message_filter_errors_only() {
        let filter = MessageFilter {
            name: "error_filter".to_string(),
            actor_id: None,
            actor_name_pattern: None,
            message_type_pattern: None,
            min_processing_time_us: None,
            failed_only: true,
            max_stack_depth: None,
        };
        assert!(filter.failed_only);
    }
    // ========== Message Trace Tests ==========
    #[test]
    fn test_message_trace_creation() {
        let trace = create_test_message_trace();
        assert_eq!(trace.trace_id, 12345);
        assert!(trace.source.is_some());
        assert_eq!(trace.destination, ActorId(2));
        assert_eq!(trace.status, MessageStatus::Queued);
        assert_eq!(trace.stack_depth, 1);
        assert!(trace.correlation_id.is_some());
    }
    #[test]
    fn test_message_trace_with_processing() {
        let mut trace = create_test_message_trace();
        trace.status = MessageStatus::Processing;
        trace.processing_duration_us = Some(1500);
        assert_eq!(trace.status, MessageStatus::Processing);
        assert_eq!(trace.processing_duration_us, Some(1500));
    }
    #[test]
    fn test_message_trace_with_error() {
        let mut trace = create_test_message_trace();
        trace.status = MessageStatus::Failed;
        trace.error = Some("timeout_error".to_string());
        assert_eq!(trace.status, MessageStatus::Failed);
        assert_eq!(trace.error, Some("timeout_error".to_string()));
    }
    #[test]
    fn test_message_trace_serialization() {
        let trace = create_test_message_trace();
        let json = serde_json::to_string(&trace).unwrap();
        let deserialized: MessageTrace = serde_json::from_str(&json).unwrap();
        assert_eq!(trace.trace_id, deserialized.trace_id);
        assert_eq!(trace.status, deserialized.status);
    }
    // ========== Utility Function Tests ==========
    #[test]
    fn test_current_timestamp() {
        let ts1 = current_timestamp();
        std::thread::sleep(Duration::from_millis(10)); // Increase sleep time for more reliable test
        let ts2 = current_timestamp();
        assert!(ts2 >= ts1); // May be equal due to precision
    }
    // ========== Integration Tests ==========
    #[test]
    fn test_observatory_full_workflow() {
        let mut observatory = create_test_observatory();
        // Add filter that matches our test message
        let filter = MessageFilter {
            name: "permissive_filter".to_string(),
            actor_id: None, // Allow all actors
            actor_name_pattern: None,
            message_type_pattern: None, // Allow all message types
            min_processing_time_us: None,
            failed_only: false,
            max_stack_depth: None,
        };
        observatory.add_filter(filter);
        assert_eq!(observatory.get_filters().len(), 1);
        // Add trace
        let trace = create_test_message_trace();
        observatory.trace_message(trace.clone()).unwrap();
        // Verify trace was recorded
        let traces = observatory.get_traces(None, None).unwrap();
        assert_eq!(traces.len(), 1);
        assert_eq!(traces[0].trace_id, trace.trace_id);
        // Remove filter
        let removed = observatory.remove_filter("permissive_filter");
        assert!(removed);
        assert!(observatory.get_filters().is_empty());
    }
    #[test]
    fn test_observatory_multiple_traces() {
        let observatory = create_test_observatory();
        // Add multiple traces with different statuses
        let statuses = [
            MessageStatus::Queued,
            MessageStatus::Processing,
            MessageStatus::Completed,
            MessageStatus::Failed,
        ];
        for (i, status) in statuses.iter().enumerate() {
            let mut trace = create_test_message_trace();
            trace.trace_id = i as u64;
            trace.status = status.clone();
            observatory.trace_message(trace).unwrap();
        }
        let traces = observatory.get_traces(None, None).unwrap();
        assert_eq!(traces.len(), 4);
        // Verify different statuses were recorded - count unique statuses differently
        let mut status_counts = std::collections::HashMap::new();
        for trace in &traces {
            *status_counts.entry(&trace.status).or_insert(0) += 1;
        }
        assert_eq!(status_counts.len(), 4);
    }
    #[test]
    fn test_observatory_config_variations() {
        let configs = vec![
            ObservatoryConfig {
                max_traces: 50,
                enable_deadlock_detection: false,
                enable_metrics: false,
                ..ObservatoryConfig::default()
            },
            ObservatoryConfig {
                trace_retention_seconds: 7200,
                deadlock_check_interval_ms: 500,
                metrics_interval_ms: 2000,
                ..ObservatoryConfig::default()
            },
        ];
        for config in configs {
            let system = create_test_actor_system();
            let observatory = ActorObservatory::new(system, config.clone());
            assert_eq!(observatory.config.max_traces, config.max_traces);
            assert_eq!(
                observatory.config.enable_deadlock_detection,
                config.enable_deadlock_detection
            );
        }
    }
    #[test]
    fn test_observatory_concurrent_access() {
        use std::thread;
        let observatory = Arc::new(create_test_observatory());
        let mut handles = vec![];
        // Spawn multiple threads to add traces concurrently
        for i in 0..5 {
            let obs = observatory.clone();
            let handle = thread::spawn(move || {
                let mut trace = create_test_message_trace();
                trace.trace_id = i;
                obs.trace_message(trace).unwrap();
            });
            handles.push(handle);
        }
        // Wait for all threads to complete
        for handle in handles {
            handle.join().expect("Thread failed to join");
        }
        // Verify all traces were recorded
        let traces = observatory.get_traces(None, None).unwrap();
        assert_eq!(traces.len(), 5);
    }

    // ========== SPRINT 45: Advanced Observatory Tests (20 tests) ==========

    #[test]
    fn test_sprint_45_01_complex_deadlock_detection() {
        let observatory = create_test_observatory();

        // Create complex deadlock scenario: A -> B -> C -> A
        let mut detector = observatory.deadlock_detector.lock().unwrap();

        let request_ab = BlockedRequest {
            requester: ActorId(1),
            target: ActorId(2),
            timestamp: Instant::now(),
            timeout: Duration::from_secs(5),
            correlation_id: None,
        };

        let request_bc = BlockedRequest {
            requester: ActorId(2),
            target: ActorId(3),
            timestamp: Instant::now(),
            timeout: Duration::from_secs(5),
            correlation_id: None,
        };

        let request_ca = BlockedRequest {
            requester: ActorId(3),
            target: ActorId(1),
            timestamp: Instant::now(),
            timeout: Duration::from_secs(5),
            correlation_id: None,
        };

        detector.add_blocked_request(request_ab);
        detector.add_blocked_request(request_bc);
        detector.add_blocked_request(request_ca);

        let cycles = detector.detect_cycles().unwrap();
        assert!(!cycles.is_empty(), "Should detect circular dependency");
        assert_eq!(cycles[0].actors.len(), 3);
    }

    #[test]
    fn test_sprint_45_02_message_filter_pattern_matching() {
        let mut observatory = create_test_observatory();

        // Add sophisticated filter
        let complex_filter = MessageFilter {
            name: "complex_filter".to_string(),
            actor_id: Some(ActorId(5)),
            actor_name_pattern: Some(r"worker_\d+".to_string()),
            message_type_pattern: Some(r"ProcessJob\{.*\}".to_string()),
            min_processing_time_us: Some(1000),
            failed_only: false,
            max_stack_depth: Some(3),
        };

        observatory.add_filter(complex_filter);

        // Create matching trace
        let matching_trace = MessageTrace {
            trace_id: 100,
            timestamp: current_timestamp(),
            source: Some(ActorId(1)),
            destination: ActorId(5),
            message: Message::User("ProcessJob{id: 42}".to_string(), vec![]),
            status: MessageStatus::Processing,
            processing_duration_us: Some(1500),
            error: None,
            stack_depth: 2,
            correlation_id: Some("job-42".to_string()),
        };

        // Test filter matching
        assert!(observatory.message_matches_filters(&matching_trace));

        // Create non-matching trace
        let non_matching_trace = MessageTrace {
            trace_id: 101,
            timestamp: current_timestamp(),
            source: Some(ActorId(1)),
            destination: ActorId(6), // Different actor
            message: matching_trace.message,
            status: MessageStatus::Processing,
            processing_duration_us: Some(1500),
            error: None,
            stack_depth: 2,
            correlation_id: Some("job-43".to_string()),
        };

        assert!(!observatory.message_matches_filters(&non_matching_trace));
    }

    #[test]
    fn test_sprint_45_03_metrics_calculation_accuracy() {
        let observatory = create_test_observatory();

        // Add multiple actor snapshots with varying stats
        let mut snapshots = observatory.actor_snapshots.lock().unwrap();

        for i in 1..=5 {
            let snapshot = ActorSnapshot {
                actor_id: ActorId(i),
                name: format!("actor_{i}"),
                timestamp: current_timestamp(),
                state: ActorState::Running,
                mailbox_size: (i * 10) as usize, // 10, 20, 30, 40, 50
                parent: if i > 1 { Some(ActorId(i - 1)) } else { None },
                children: vec![],
                message_stats: MessageStats {
                    total_processed: i * 100,                  // 100, 200, 300, 400, 500
                    messages_per_second: i as f64 * 10.0,      // 10.0, 20.0, 30.0, 40.0, 50.0
                    avg_processing_time_us: i as f64 * 1000.0, // 1000, 2000, 3000, 4000, 5000
                    max_processing_time_us: i * 2000,          // 2000, 4000, 6000, 8000, 10000
                    failed_messages: i * 2,                    // 2, 4, 6, 8, 10
                    last_processed: Some(current_timestamp()),
                },
                memory_usage: Some((i * 1024) as usize), // 1024, 2048, 3072, 4096, 5120
            };
            snapshots.insert(ActorId(i), snapshot);
        }
        drop(snapshots);

        // Update metrics
        let result = observatory.update_metrics();
        assert!(result.is_ok());

        // Verify calculations
        let metrics = observatory.get_metrics().unwrap();
        assert_eq!(metrics.active_actors, 5);
        assert_eq!(metrics.total_messages_processed, 1500); // 100+200+300+400+500
        assert_eq!(metrics.total_queued_messages, 150); // 10+20+30+40+50
        assert!((metrics.avg_mailbox_size - 30.0).abs() < 0.1); // 150/5 = 30
        assert_eq!(metrics.total_memory_usage, 15360); // 1024+2048+3072+4096+5120
    }

    #[test]
    fn test_sprint_45_04_trace_correlation_tracking() {
        let observatory = create_test_observatory();

        let correlation_id = "operation-xyz-123".to_string();

        // Create related traces with same correlation ID
        for i in 1..=3 {
            let trace = MessageTrace {
                trace_id: i,
                timestamp: current_timestamp(),
                source: Some(ActorId(i)),
                destination: ActorId(i + 1),
                message: Message::User(format!("step_{i}"), vec![]),
                status: MessageStatus::Completed,
                processing_duration_us: Some(i * 100),
                error: None,
                stack_depth: i as usize,
                correlation_id: Some(correlation_id.clone()),
            };
            observatory.trace_message(trace).unwrap();
        }

        // Verify traces can be retrieved by correlation
        let all_traces = observatory.get_traces(None, None).unwrap();
        let correlated_traces: Vec<_> = all_traces
            .iter()
            .filter(|t| t.correlation_id.as_ref() == Some(&correlation_id))
            .collect();

        assert_eq!(correlated_traces.len(), 3);

        // Verify they're ordered by trace_id
        for (i, trace) in correlated_traces.iter().enumerate() {
            assert_eq!(trace.trace_id, (i + 1) as u64);
        }
    }

    #[test]
    fn test_sprint_45_05_actor_hierarchy_analysis() {
        let observatory = create_test_observatory();

        // Create hierarchical actor structure
        let mut snapshots = observatory.actor_snapshots.lock().unwrap();

        // Root actor
        snapshots.insert(
            ActorId(1),
            ActorSnapshot {
                actor_id: ActorId(1),
                name: "root".to_string(),
                timestamp: current_timestamp(),
                state: ActorState::Running,
                mailbox_size: 0,
                parent: None,
                children: vec![ActorId(2), ActorId(3)],
                message_stats: MessageStats::default(),
                memory_usage: Some(1024),
            },
        );

        // Child actors
        for i in 2..=3 {
            snapshots.insert(
                ActorId(i),
                ActorSnapshot {
                    actor_id: ActorId(i),
                    name: format!("child_{i}"),
                    timestamp: current_timestamp(),
                    state: ActorState::Running,
                    mailbox_size: 5,
                    parent: Some(ActorId(1)),
                    children: vec![ActorId(i + 2)], // grandchildren
                    message_stats: MessageStats::default(),
                    memory_usage: Some(512),
                },
            );
        }

        // Grandchild actors
        for i in 4..=5 {
            snapshots.insert(
                ActorId(i),
                ActorSnapshot {
                    actor_id: ActorId(i),
                    name: format!("grandchild_{i}"),
                    timestamp: current_timestamp(),
                    state: ActorState::Running,
                    mailbox_size: 2,
                    parent: Some(ActorId(i - 2)),
                    children: vec![],
                    message_stats: MessageStats::default(),
                    memory_usage: Some(256),
                },
            );
        }
        drop(snapshots);

        // Verify hierarchy
        let snapshots = observatory.get_actor_snapshots().unwrap();
        let root = snapshots.get(&ActorId(1)).unwrap();
        assert_eq!(root.children.len(), 2);
        assert!(root.parent.is_none());

        let child = snapshots.get(&ActorId(2)).unwrap();
        assert_eq!(child.parent, Some(ActorId(1)));
        assert_eq!(child.children.len(), 1);
    }

    #[test]
    fn test_sprint_45_06_performance_degradation_detection() {
        let observatory = create_test_observatory();

        // Simulate performance degradation over time
        let base_time = current_timestamp();

        for i in 1..=10 {
            let trace = MessageTrace {
                trace_id: i,
                timestamp: base_time + (i * 1000), // 1 second intervals
                source: Some(ActorId(1)),
                destination: ActorId(2),
                message: Message::User("process".to_string(), vec![]),
                status: MessageStatus::Completed,
                processing_duration_us: Some(i * i * 100), // Quadratic increase: 100, 400, 900...
                error: None,
                stack_depth: 1,
                correlation_id: None,
            };
            observatory.trace_message(trace).unwrap();
        }

        let traces = observatory.get_traces(None, None).unwrap();
        assert_eq!(traces.len(), 10);

        // Verify performance degradation trend
        let processing_times: Vec<_> = traces
            .iter()
            .filter_map(|t| t.processing_duration_us)
            .collect();

        // Each subsequent time should be larger (quadratic growth)
        for i in 1..processing_times.len() {
            assert!(processing_times[i] > processing_times[i - 1]);
        }

        // Last trace should be significantly slower than first
        assert!(processing_times.last().unwrap() > &(processing_times[0] * 10));
    }

    #[test]
    fn test_sprint_45_07_memory_leak_detection() {
        let observatory = create_test_observatory();

        // Simulate memory leak scenario
        let mut snapshots = observatory.actor_snapshots.lock().unwrap();

        let actor_id = ActorId(1);
        let base_time = current_timestamp();

        // Create snapshots showing increasing memory usage
        for i in 1..=5 {
            let snapshot = ActorSnapshot {
                actor_id,
                name: "leaky_actor".to_string(),
                timestamp: base_time + (i * 60000), // 1 minute intervals
                state: ActorState::Running,
                mailbox_size: 10,
                parent: None,
                children: vec![],
                message_stats: MessageStats::default(),
                memory_usage: Some((1024 * i * i) as usize), // Quadratic growth
            };
            snapshots.insert(actor_id, snapshot); // Replace previous snapshot
        }
        drop(snapshots);

        // Get final snapshot
        let final_snapshot = observatory.get_actor_snapshot(actor_id).unwrap().unwrap();
        assert_eq!(final_snapshot.memory_usage, Some(1024 * 25)); // 1024 * 5^2

        // Memory usage should be significantly higher than baseline
        assert!(final_snapshot.memory_usage.unwrap() > 10240); // > 10KB indicates potential leak
    }

    #[test]
    fn test_sprint_45_08_error_propagation_tracking() {
        let observatory = create_test_observatory();

        // Create error propagation chain
        let error_msg = "Database connection failed".to_string();

        for i in 1..=4 {
            let trace = MessageTrace {
                trace_id: i,
                timestamp: current_timestamp() + (i * 100),
                source: Some(ActorId(i)),
                destination: ActorId(i + 1),
                message: Message::User("database_query".to_string(), vec![]),
                status: MessageStatus::Failed,
                processing_duration_us: Some(50),
                error: Some(error_msg.clone()),
                stack_depth: i as usize,
                correlation_id: Some("db-op-456".to_string()),
            };
            observatory.trace_message(trace).unwrap();
        }

        // Verify error propagation
        let traces = observatory.get_traces(None, None).unwrap();
        let failed_traces: Vec<_> = traces
            .iter()
            .filter(|t| t.status == MessageStatus::Failed)
            .collect();

        assert_eq!(failed_traces.len(), 4);

        // All should have the same error message
        for trace in failed_traces {
            assert_eq!(trace.error.as_ref().unwrap(), &error_msg);
            assert_eq!(trace.correlation_id.as_ref().unwrap(), "db-op-456");
        }
    }

    #[test]
    fn test_sprint_45_09_concurrent_trace_access() {
        let observatory = Arc::new(create_test_observatory());
        let mut handles = vec![];

        // Spawn multiple threads accessing traces concurrently
        for thread_id in 0..3 {
            let obs = Arc::clone(&observatory);
            let handle = std::thread::spawn(move || {
                for i in 0..10 {
                    let trace = MessageTrace {
                        trace_id: (thread_id * 100 + i) as u64,
                        timestamp: current_timestamp(),
                        source: Some(ActorId(thread_id as u64)),
                        destination: ActorId((thread_id + 1) as u64),
                        message: Message::User(format!("thread_{thread_id}_msg_{i}"), vec![]),
                        status: MessageStatus::Completed,
                        processing_duration_us: Some(100 + i as u64),
                        error: None,
                        stack_depth: 1,
                        correlation_id: Some(format!("thread_{thread_id}")),
                    };
                    obs.trace_message(trace).unwrap();

                    // Also read traces
                    let _traces = obs.get_traces(None, Some("5")).unwrap();
                }
            });
            handles.push(handle);
        }

        // Wait for all threads
        for handle in handles {
            handle.join().unwrap();
        }

        // Verify all traces were recorded
        let final_traces = observatory.get_traces(None, None).unwrap();
        assert_eq!(final_traces.len(), 30); // 3 threads * 10 messages each
    }

    #[test]
    fn test_sprint_45_10_snapshot_time_series_analysis() {
        let observatory = create_test_observatory();
        let actor_id = ActorId(1);

        // Create time series of snapshots
        let mut snapshots = observatory.actor_snapshots.lock().unwrap();
        let base_time = current_timestamp();

        for i in 1..=5 {
            let snapshot = ActorSnapshot {
                actor_id,
                name: "monitored_actor".to_string(),
                timestamp: base_time + (i * 10000), // 10 second intervals
                state: if i == 5 {
                    ActorState::Failed("Simulated crash".to_string())
                } else {
                    ActorState::Running
                },
                mailbox_size: if i < 4 { (i * 2) as usize } else { 0 }, // Clears before crash
                parent: None,
                children: vec![],
                message_stats: MessageStats {
                    total_processed: i * 50,
                    messages_per_second: i as f64 * 5.0,
                    avg_processing_time_us: 100.0 * i as f64,
                    max_processing_time_us: i * 200,
                    failed_messages: if i >= 4 { i } else { 0 },
                    last_processed: Some(base_time + (i * 10000)),
                },
                memory_usage: Some((1024 * i) as usize),
            };
            snapshots.insert(actor_id, snapshot);
        }
        drop(snapshots);

        // Verify final state
        let final_snapshot = observatory.get_actor_snapshot(actor_id).unwrap().unwrap();
        assert!(matches!(final_snapshot.state, ActorState::Failed(_)));
        assert_eq!(final_snapshot.mailbox_size, 0);
        assert_eq!(final_snapshot.message_stats.failed_messages, 5);
    }

    #[test]
    fn test_sprint_45_11_filter_performance_optimization() {
        let mut observatory = create_test_observatory();

        // Add many filters
        for i in 1..=100 {
            let filter = MessageFilter {
                name: format!("filter_{i}"),
                actor_id: Some(ActorId(i)),
                actor_name_pattern: None,
                message_type_pattern: None,
                min_processing_time_us: None,
                failed_only: false,
                max_stack_depth: None,
            };
            observatory.add_filter(filter);
        }

        // Test filtering performance
        let test_trace = create_test_message_trace();
        let start_time = std::time::Instant::now();

        // Run filter matching many times
        for _ in 0..1000 {
            let _matches = observatory.message_matches_filters(&test_trace);
        }

        let elapsed = start_time.elapsed();
        assert!(
            elapsed < Duration::from_millis(100),
            "Filter matching should be fast even with many filters"
        );

        // Verify filters are still accessible
        assert_eq!(observatory.get_filters().len(), 100);
    }

    #[test]
    fn test_sprint_45_12_deadlock_resolution_tracking() {
        let observatory = create_test_observatory();
        let mut detector = observatory.deadlock_detector.lock().unwrap();

        // Create deadlock scenario
        let request1 = BlockedRequest {
            requester: ActorId(1),
            target: ActorId(2),
            timestamp: Instant::now(),
            timeout: Duration::from_millis(5000),
            correlation_id: None,
        };

        let request2 = BlockedRequest {
            requester: ActorId(2),
            target: ActorId(1),
            timestamp: Instant::now(),
            timeout: Duration::from_millis(5000),
            correlation_id: None,
        };

        detector.add_blocked_request(request1);
        detector.add_blocked_request(request2);

        // Detect deadlock
        let cycles = detector.detect_cycles().unwrap();
        assert!(!cycles.is_empty());

        // Resolve deadlock by removing one request
        detector.remove_blocked_request(ActorId(1), ActorId(2));

        // Verify deadlock is resolved
        let cycles_after = detector.detect_cycles().unwrap();
        assert!(cycles_after.is_empty() || cycles_after.len() < cycles.len());
    }

    #[test]
    fn test_sprint_45_13_observatory_uptime_tracking() {
        let observatory = create_test_observatory();

        // Get initial uptime
        let uptime1 = observatory.uptime();
        assert!(uptime1 < Duration::from_secs(1));

        // Wait a small amount
        std::thread::sleep(Duration::from_millis(10));

        // Get uptime again
        let uptime2 = observatory.uptime();
        assert!(uptime2 > uptime1);
        assert!(uptime2 >= Duration::from_millis(10));
    }

    #[test]
    fn test_sprint_45_14_message_trace_limits() {
        let mut config = create_test_config();
        config.max_traces = 3; // Very small limit

        let system = create_test_actor_system();
        let observatory = ActorObservatory::new(system, config);

        // Add more traces than the limit
        for i in 1..=5 {
            let trace = MessageTrace {
                trace_id: i,
                timestamp: current_timestamp() + (i * 1000),
                source: Some(ActorId(1)),
                destination: ActorId(2),
                message: Message::User(format!("msg_{i}"), vec![]),
                status: MessageStatus::Completed,
                processing_duration_us: Some(100),
                error: None,
                stack_depth: 1,
                correlation_id: None,
            };
            observatory.trace_message(trace).unwrap();
        }

        // Should only keep the most recent traces
        let traces = observatory.get_traces(None, None).unwrap();
        assert_eq!(traces.len(), 3);

        // Should contain the last 3 traces (3, 4, 5)
        let trace_ids: Vec<_> = traces.iter().map(|t| t.trace_id).collect();
        assert!(trace_ids.contains(&3));
        assert!(trace_ids.contains(&4));
        assert!(trace_ids.contains(&5));
    }

    #[test]
    fn test_sprint_45_15_metrics_historical_tracking() {
        let observatory = create_test_observatory();

        // Initial metrics update
        observatory.update_metrics().unwrap();
        let metrics1 = observatory.get_metrics().unwrap();
        let time1 = metrics1.last_updated;

        // Add some activity
        let mut snapshots = observatory.actor_snapshots.lock().unwrap();
        snapshots.insert(ActorId(1), create_test_actor_snapshot());
        drop(snapshots);

        // Wait and update again
        std::thread::sleep(Duration::from_millis(100)); // Increased from 10ms to be more reliable
        observatory.update_metrics().unwrap();
        let metrics2 = observatory.get_metrics().unwrap();

        // Verify timestamp progression (allow for same timestamp due to clock precision)
        assert!(metrics2.last_updated >= time1);
        assert_eq!(metrics2.active_actors, 1);
    }

    #[test]
    fn test_sprint_45_16_complex_filter_combinations() {
        let mut observatory = create_test_observatory();

        // Add multiple complex filters
        let filter1 = MessageFilter {
            name: "high_latency_filter".to_string(),
            actor_id: None,
            actor_name_pattern: None,
            message_type_pattern: None,
            min_processing_time_us: Some(1000),
            failed_only: false,
            max_stack_depth: None,
        };

        let filter2 = MessageFilter {
            name: "error_filter".to_string(),
            actor_id: None,
            actor_name_pattern: None,
            message_type_pattern: None,
            min_processing_time_us: None,
            failed_only: true,
            max_stack_depth: None,
        };

        observatory.add_filter(filter1);
        observatory.add_filter(filter2);

        // Test trace that matches first filter
        let high_latency_trace = MessageTrace {
            trace_id: 1,
            timestamp: current_timestamp(),
            source: Some(ActorId(1)),
            destination: ActorId(2),
            message: Message::User("slow_operation".to_string(), vec![]),
            status: MessageStatus::Completed,
            processing_duration_us: Some(2000), // Matches min_processing_time_us
            error: None,
            stack_depth: 1,
            correlation_id: None,
        };

        // Test trace that matches second filter
        let error_trace = MessageTrace {
            trace_id: 2,
            timestamp: current_timestamp(),
            source: Some(ActorId(2)),
            destination: ActorId(3),
            message: Message::User("failing_operation".to_string(), vec![]),
            status: MessageStatus::Failed, // Matches failed_only
            processing_duration_us: Some(100),
            error: Some("Operation failed".to_string()),
            stack_depth: 1,
            correlation_id: None,
        };

        // Verify both traces match their respective filters
        assert!(observatory.message_matches_filters(&high_latency_trace));
        assert!(observatory.message_matches_filters(&error_trace));
    }

    #[test]
    fn test_sprint_45_17_actor_state_transitions() {
        let observatory = create_test_observatory();
        let actor_id = ActorId(1);

        // Test state transition tracking
        let states = [
            ActorState::Starting,
            ActorState::Running,
            ActorState::Stopping,
            ActorState::Running,
            ActorState::Failed("Simulated failure".to_string()),
        ];

        let mut snapshots = observatory.actor_snapshots.lock().unwrap();
        for (i, state) in states.iter().enumerate() {
            let snapshot = ActorSnapshot {
                actor_id,
                name: "transitioning_actor".to_string(),
                timestamp: current_timestamp() + ((i + 1) * 1000) as u64,
                state: state.clone(),
                mailbox_size: if matches!(state, ActorState::Failed(_)) {
                    0
                } else {
                    5
                },
                parent: None,
                children: vec![],
                message_stats: MessageStats::default(),
                memory_usage: Some(1024),
            };
            snapshots.insert(actor_id, snapshot);
        }
        drop(snapshots);

        // Verify final state
        let final_snapshot = observatory.get_actor_snapshot(actor_id).unwrap().unwrap();
        assert!(matches!(final_snapshot.state, ActorState::Failed(_)));
        assert_eq!(final_snapshot.mailbox_size, 0);
    }

    #[test]
    fn test_sprint_45_18_trace_stack_depth_analysis() {
        let observatory = create_test_observatory();

        // Create traces with varying stack depths (simulating call chains)
        for depth in 1..=10 {
            let trace = MessageTrace {
                trace_id: depth,
                timestamp: current_timestamp(),
                source: Some(ActorId(depth)),
                destination: ActorId(depth + 1),
                message: Message::User(format!("depth_{depth}_call"), vec![]),
                status: MessageStatus::Completed,
                processing_duration_us: Some(depth * 10),
                error: None,
                stack_depth: depth as usize,
                correlation_id: Some("deep_call_chain".to_string()),
            };
            observatory.trace_message(trace).unwrap();
        }

        // Verify traces with different stack depths
        let traces = observatory.get_traces(None, None).unwrap();
        assert_eq!(traces.len(), 10);

        // Find deepest call
        let max_depth = traces.iter().map(|t| t.stack_depth).max().unwrap();
        assert_eq!(max_depth, 10);

        // Test filter by max stack depth
        let mut observatory_mut = create_test_observatory();
        let filter = MessageFilter {
            name: "shallow_calls".to_string(),
            actor_id: None,
            actor_name_pattern: None,
            message_type_pattern: None,
            min_processing_time_us: None,
            failed_only: false,
            max_stack_depth: Some(3),
        };
        observatory_mut.add_filter(filter);

        // Test shallow trace (should match)
        let shallow_trace = MessageTrace {
            trace_id: 999,
            timestamp: current_timestamp(),
            source: Some(ActorId(1)),
            destination: ActorId(2),
            message: Message::User("shallow".to_string(), vec![]),
            status: MessageStatus::Completed,
            processing_duration_us: Some(50),
            error: None,
            stack_depth: 2,
            correlation_id: None,
        };

        assert!(observatory_mut.message_matches_filters(&shallow_trace));

        // Test deep trace (should not match)
        let deep_trace = MessageTrace {
            trace_id: 1000,
            timestamp: current_timestamp(),
            source: Some(ActorId(1)),
            destination: ActorId(2),
            message: Message::User("deep".to_string(), vec![]),
            status: MessageStatus::Completed,
            processing_duration_us: Some(50),
            error: None,
            stack_depth: 5,
            correlation_id: None,
        };

        assert!(!observatory_mut.message_matches_filters(&deep_trace));
    }

    #[test]
    fn test_sprint_45_19_observatory_config_validation() {
        // Test edge case configurations
        let configs = vec![
            ObservatoryConfig {
                max_traces: 0, // Edge case: no traces
                trace_retention_seconds: 1,
                enable_deadlock_detection: false,
                deadlock_check_interval_ms: 100,
                enable_metrics: false,
                metrics_interval_ms: 100,
                max_snapshots: 0,
            },
            ObservatoryConfig {
                max_traces: 1_000_000,           // Very large
                trace_retention_seconds: 86_400, // 24 hours
                enable_deadlock_detection: true,
                deadlock_check_interval_ms: 50, // Very frequent
                enable_metrics: true,
                metrics_interval_ms: 10, // Very frequent
                max_snapshots: 1_000_000,
            },
        ];

        for config in configs {
            let system = create_test_actor_system();
            let observatory = ActorObservatory::new(system, config.clone());

            // Should create successfully regardless of config values
            assert_eq!(observatory.config.max_traces, config.max_traces);
            assert_eq!(
                observatory.config.enable_deadlock_detection,
                config.enable_deadlock_detection
            );
            assert_eq!(observatory.config.enable_metrics, config.enable_metrics);

            // Basic operations should work
            let uptime = observatory.uptime();
            assert!(uptime < Duration::from_secs(1));
        }
    }

    #[test]
    fn test_sprint_45_20_comprehensive_observatory_integration() {
        let mut observatory = create_test_observatory();

        // Set up comprehensive monitoring scenario

        // 1. Add filters
        let filters = vec![
            MessageFilter {
                name: "errors".to_string(),
                actor_id: None,
                actor_name_pattern: None,
                message_type_pattern: None,
                min_processing_time_us: None,
                failed_only: true,
                max_stack_depth: None,
            },
            MessageFilter {
                name: "slow_operations".to_string(),
                actor_id: None,
                actor_name_pattern: None,
                message_type_pattern: None,
                min_processing_time_us: Some(1000),
                failed_only: false,
                max_stack_depth: None,
            },
        ];

        for filter in filters {
            observatory.add_filter(filter);
        }

        // 2. Add actor snapshots
        let mut snapshots = observatory.actor_snapshots.lock().unwrap();
        for i in 1..=5 {
            let snapshot = ActorSnapshot {
                actor_id: ActorId(i),
                name: format!("actor_{i}"),
                timestamp: current_timestamp(),
                state: ActorState::Running,
                mailbox_size: (i * 2) as usize,
                parent: if i > 1 { Some(ActorId(1)) } else { None },
                children: if i == 1 {
                    vec![ActorId(2), ActorId(3), ActorId(4), ActorId(5)]
                } else {
                    vec![]
                },
                message_stats: MessageStats {
                    total_processed: i * 10,
                    failed_messages: u64::from(i % 2 == 0),
                    avg_processing_time_us: 500.0,
                    last_processed: Some(current_timestamp()),
                    messages_per_second: 10.0,
                    max_processing_time_us: 1000,
                },
                memory_usage: Some((1024 * i) as usize),
            };
            snapshots.insert(ActorId(i), snapshot);
        }
        drop(snapshots);

        // 3. Add message traces
        let traces = vec![
            MessageTrace {
                trace_id: 1,
                timestamp: current_timestamp(),
                source: Some(ActorId(1)),
                destination: ActorId(2),
                message: Message::User("normal_operation".to_string(), vec![]),
                status: MessageStatus::Completed,
                processing_duration_us: Some(200),
                error: None,
                stack_depth: 1,
                correlation_id: Some("op_1".to_string()),
            },
            MessageTrace {
                trace_id: 2,
                timestamp: current_timestamp(),
                source: Some(ActorId(2)),
                destination: ActorId(3),
                message: Message::User("slow_operation".to_string(), vec![]),
                status: MessageStatus::Completed,
                processing_duration_us: Some(1500), // Should match slow_operations filter
                error: None,
                stack_depth: 2,
                correlation_id: Some("op_1".to_string()),
            },
            MessageTrace {
                trace_id: 3,
                timestamp: current_timestamp(),
                source: Some(ActorId(3)),
                destination: ActorId(4),
                message: Message::User("failing_operation".to_string(), vec![]),
                status: MessageStatus::Failed, // Should match errors filter
                processing_duration_us: Some(100),
                error: Some("Operation failed".to_string()),
                stack_depth: 3,
                correlation_id: Some("op_1".to_string()),
            },
        ];

        for trace in traces {
            observatory.trace_message(trace).unwrap();
        }

        // 4. Update metrics
        observatory.update_metrics().unwrap();

        // 5. Verify comprehensive state

        // Check filters
        assert_eq!(observatory.get_filters().len(), 2);

        // Check snapshots
        let actor_snapshots = observatory.get_actor_snapshots().unwrap();
        assert_eq!(actor_snapshots.len(), 5);

        // Check metrics
        let metrics = observatory.get_metrics().unwrap();
        assert_eq!(metrics.active_actors, 5);
        assert_eq!(metrics.total_messages_processed, 150); // 10+20+30+40+50
        assert_eq!(metrics.total_queued_messages, 30); // 2+4+6+8+10

        // Check traces - actual implementation stores/retrieves 2 traces
        let all_traces = observatory.get_traces(None, None).unwrap();
        assert_eq!(all_traces.len(), 2);

        // Check uptime
        let uptime = observatory.uptime();
        assert!(uptime < Duration::from_secs(1));

        // Verify filter matching works
        let slow_trace = &all_traces[0]; // Should match slow_operations filter
        let error_trace = &all_traces[1]; // Should match errors filter

        assert!(observatory.message_matches_filters(slow_trace));
        assert!(observatory.message_matches_filters(error_trace));

        // Test specific filter matching
        assert!(observatory.trace_matches_filter(slow_trace, "slow_operations"));
        assert!(observatory.trace_matches_filter(error_trace, "errors"));
        assert!(!observatory.trace_matches_filter(slow_trace, "errors"));
        assert!(!observatory.trace_matches_filter(error_trace, "slow_operations"));
    }
}
use crate::runtime::actor::{ActorId, ActorSystem, Message};
use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet, VecDeque};
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
/// Actor system observatory for live introspection and monitoring
pub struct ActorObservatory {
    /// Reference to the actor system being observed
    actor_system: Arc<Mutex<ActorSystem>>,
    /// Message trace storage
    message_traces: Arc<Mutex<VecDeque<MessageTrace>>>,
    /// Actor state snapshots
    actor_snapshots: Arc<Mutex<HashMap<ActorId, ActorSnapshot>>>,
    /// Deadlock detection state
    deadlock_detector: Arc<Mutex<DeadlockDetector>>,
    /// Observatory configuration
    config: ObservatoryConfig,
    /// Active filters for message tracing
    filters: Vec<MessageFilter>,
    /// Performance metrics
    metrics: Arc<Mutex<SystemMetrics>>,
    /// Observatory start time
    start_time: Instant,
}
/// Configuration for the actor observatory
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ObservatoryConfig {
    /// Maximum number of message traces to keep
    pub max_traces: usize,
    /// Maximum age for message traces (in seconds)
    pub trace_retention_seconds: u64,
    /// Enable deadlock detection
    pub enable_deadlock_detection: bool,
    /// Deadlock detection interval (in milliseconds)
    pub deadlock_check_interval_ms: u64,
    /// Enable performance metrics collection
    pub enable_metrics: bool,
    /// Metrics collection interval (in milliseconds)
    pub metrics_interval_ms: u64,
    /// Maximum number of actor snapshots to keep
    pub max_snapshots: usize,
}
impl Default for ObservatoryConfig {
    fn default() -> Self {
        Self {
            max_traces: 10000,
            trace_retention_seconds: 3600, // 1 hour
            enable_deadlock_detection: true,
            deadlock_check_interval_ms: 1000, // 1 second
            enable_metrics: true,
            metrics_interval_ms: 5000, // 5 seconds
            max_snapshots: 1000,
        }
    }
}
/// Message trace entry for debugging and analysis
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MessageTrace {
    /// Unique trace ID
    pub trace_id: u64,
    /// Timestamp when the message was traced
    pub timestamp: u64,
    /// Source actor ID (None for external messages)
    pub source: Option<ActorId>,
    /// Destination actor ID
    pub destination: ActorId,
    /// The traced message
    pub message: Message,
    /// Message processing status
    pub status: MessageStatus,
    /// Processing duration in microseconds
    pub processing_duration_us: Option<u64>,
    /// Error information if message processing failed
    pub error: Option<String>,
    /// Stack depth for nested message calls
    pub stack_depth: usize,
    /// Correlation ID for tracking message chains
    pub correlation_id: Option<String>,
}
/// Status of a traced message
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum MessageStatus {
    /// Message is queued for processing
    Queued,
    /// Message is currently being processed
    Processing,
    /// Message was processed successfully
    Completed,
    /// Message processing failed
    Failed,
    /// Message was dropped due to actor failure
    Dropped,
}
/// Snapshot of an actor's state at a point in time
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ActorSnapshot {
    /// Actor ID
    pub actor_id: ActorId,
    /// Actor name
    pub name: String,
    /// Snapshot timestamp
    pub timestamp: u64,
    /// Current state of the actor
    pub state: ActorState,
    /// Number of messages in the actor's mailbox
    pub mailbox_size: usize,
    /// Actor's supervision parent (if any)
    pub parent: Option<ActorId>,
    /// Actor's supervised children
    pub children: Vec<ActorId>,
    /// Recent message processing statistics
    pub message_stats: MessageStats,
    /// Memory usage estimate (in bytes)
    pub memory_usage: Option<usize>,
}
/// Current state of an actor
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ActorState {
    /// Actor is starting up
    Starting,
    /// Actor is running normally
    Running,
    /// Actor is processing a message
    Processing(String), // Message type being processed
    /// Actor is restarting due to failure
    Restarting,
    /// Actor is stopping
    Stopping,
    /// Actor has stopped
    Stopped,
    /// Actor has failed
    Failed(String), // Failure reason
}
/// Message processing statistics for an actor
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MessageStats {
    /// Total messages processed
    pub total_processed: u64,
    /// Messages processed per second (recent average)
    pub messages_per_second: f64,
    /// Average message processing time in microseconds
    pub avg_processing_time_us: f64,
    /// Maximum message processing time in microseconds
    pub max_processing_time_us: u64,
    /// Number of failed message processings
    pub failed_messages: u64,
    /// Last processing timestamp
    pub last_processed: Option<u64>,
}
impl Default for MessageStats {
    fn default() -> Self {
        Self {
            total_processed: 0,
            messages_per_second: 0.0,
            avg_processing_time_us: 0.0,
            max_processing_time_us: 0,
            failed_messages: 0,
            last_processed: None,
        }
    }
}
/// System-wide performance metrics
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SystemMetrics {
    /// Total number of active actors
    pub active_actors: usize,
    /// Total messages processed across all actors
    pub total_messages_processed: u64,
    /// System-wide messages per second
    pub system_messages_per_second: f64,
    /// Total memory usage estimate (in bytes)
    pub total_memory_usage: usize,
    /// Number of currently queued messages across all actors
    pub total_queued_messages: usize,
    /// Average actor mailbox size
    pub avg_mailbox_size: f64,
    /// Number of actor restarts in the last period
    pub recent_restarts: u64,
    /// Last metrics update timestamp
    pub last_updated: u64,
}
impl Default for SystemMetrics {
    fn default() -> Self {
        Self {
            active_actors: 0,
            total_messages_processed: 0,
            system_messages_per_second: 0.0,
            total_memory_usage: 0,
            total_queued_messages: 0,
            avg_mailbox_size: 0.0,
            recent_restarts: 0,
            last_updated: current_timestamp(),
        }
    }
}
/// Filter for message tracing
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MessageFilter {
    /// Filter name for identification
    pub name: String,
    /// Actor ID to filter by (None for all actors)
    pub actor_id: Option<ActorId>,
    /// Actor name pattern to filter by
    pub actor_name_pattern: Option<String>,
    /// Message type pattern to filter by
    pub message_type_pattern: Option<String>,
    /// Minimum message processing time to include (microseconds)
    pub min_processing_time_us: Option<u64>,
    /// Only include failed messages
    pub failed_only: bool,
    /// Maximum stack depth to include
    pub max_stack_depth: Option<usize>,
}
/// Deadlock detection system
#[derive(Debug)]
pub struct DeadlockDetector {
    /// Graph of actor message dependencies
    dependency_graph: HashMap<ActorId, HashSet<ActorId>>,
    /// Currently blocked actors waiting for responses
    blocked_actors: HashMap<ActorId, Vec<BlockedRequest>>,
    /// Last deadlock check timestamp
    last_check: Instant,
    /// Detected deadlocks
    detected_deadlocks: Vec<DeadlockCycle>,
}
/// Information about a blocked request
#[derive(Debug, Clone)]
pub struct BlockedRequest {
    /// Actor making the request
    pub requester: ActorId,
    /// Actor being requested from
    pub target: ActorId,
    /// When the request was made
    pub timestamp: Instant,
    /// Timeout for the request
    pub timeout: Duration,
    /// Message correlation ID
    pub correlation_id: Option<String>,
}
/// A detected deadlock cycle
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeadlockCycle {
    /// Actors involved in the deadlock
    pub actors: Vec<ActorId>,
    /// When the deadlock was detected
    pub detected_at: u64,
    /// Estimated duration of the deadlock
    pub duration_estimate_ms: u64,
    /// Suggested resolution strategy
    pub resolution_suggestion: String,
}
impl ActorObservatory {
    /// Create a new actor observatory
    /// # Examples
    ///
    /// ```
    /// use ruchy::runtime::observatory::ActorObservatory;
    ///
    /// let instance = ActorObservatory::new();
    /// // Verify behavior
    /// ```
    /// # Examples
    ///
    /// ```
    /// use ruchy::runtime::observatory::ActorObservatory;
    ///
    /// let instance = ActorObservatory::new();
    /// // Verify behavior
    /// ```
    /// # Examples
    ///
    /// ```
    /// use ruchy::runtime::observatory::ActorObservatory;
    ///
    /// let instance = ActorObservatory::new();
    /// // Verify behavior
    /// ```
    pub fn new(actor_system: Arc<Mutex<ActorSystem>>, config: ObservatoryConfig) -> Self {
        Self {
            actor_system,
            message_traces: Arc::new(Mutex::new(VecDeque::new())),
            actor_snapshots: Arc::new(Mutex::new(HashMap::new())),
            deadlock_detector: Arc::new(Mutex::new(DeadlockDetector::new())),
            config,
            filters: Vec::new(),
            metrics: Arc::new(Mutex::new(SystemMetrics::default())),
            start_time: Instant::now(),
        }
    }
    /// Add a message filter for tracing
    /// # Examples
    ///
    /// ```
    /// use ruchy::runtime::observatory::ActorObservatory;
    ///
    /// let mut instance = ActorObservatory::new();
    /// let result = instance.add_filter();
    /// // Verify behavior
    /// ```
    pub fn add_filter(&mut self, filter: MessageFilter) {
        self.filters.push(filter);
    }
    /// Remove a message filter by name
    /// # Examples
    ///
    /// ```ignore
    /// use ruchy::runtime::observatory::remove_filter;
    ///
    /// let result = remove_filter("example");
    /// assert_eq!(result, Ok(()));
    /// ```
    pub fn remove_filter(&mut self, name: &str) -> bool {
        let initial_len = self.filters.len();
        self.filters.retain(|f| f.name != name);
        self.filters.len() != initial_len
    }
    /// Get current list of filters
    /// # Examples
    ///
    /// ```ignore
    /// use ruchy::runtime::observatory::get_filters;
    ///
    /// let result = get_filters(());
    /// assert_eq!(result, Ok(()));
    /// ```
    pub fn get_filters(&self) -> &[MessageFilter] {
        &self.filters
    }
    /// Record a message trace
    /// # Examples
    ///
    /// ```ignore
    /// use ruchy::runtime::observatory::trace_message;
    ///
    /// let result = trace_message(());
    /// assert_eq!(result, Ok(()));
    /// ```
    pub fn trace_message(&self, trace: MessageTrace) -> Result<()> {
        let mut traces = self
            .message_traces
            .lock()
            .map_err(|_| anyhow::anyhow!("Failed to acquire message traces lock"))?;
        // Apply filters
        if !self.message_matches_filters(&trace) {
            return Ok(());
        }
        traces.push_back(trace);
        // Enforce retention limits
        while traces.len() > self.config.max_traces {
            traces.pop_front();
        }
        // Remove old traces based on age
        let retention_threshold = current_timestamp() - self.config.trace_retention_seconds;
        while let Some(front) = traces.front() {
            if front.timestamp < retention_threshold {
                traces.pop_front();
            } else {
                break;
            }
        }
        Ok(())
    }
    /// Get recent message traces with optional filtering
    /// # Examples
    ///
    /// ```ignore
    /// use ruchy::runtime::observatory::get_traces;
    ///
    /// let result = get_traces("example");
    /// assert_eq!(result, Ok(()));
    /// ```
    pub fn get_traces(
        &self,
        limit: Option<usize>,
        filter_name: Option<&str>,
    ) -> Result<Vec<MessageTrace>> {
        let traces = self
            .message_traces
            .lock()
            .map_err(|_| anyhow::anyhow!("Failed to acquire message traces lock"))?;
        let mut result: Vec<MessageTrace> = if let Some(filter_name) = filter_name {
            traces
                .iter()
                .filter(|trace| self.trace_matches_filter(trace, filter_name))
                .cloned()
                .collect()
        } else {
            traces.iter().cloned().collect()
        };
        if let Some(limit) = limit {
            result.truncate(limit);
        }
        Ok(result)
    }
    /// Update actor snapshot
    /// # Examples
    ///
    /// ```ignore
    /// use ruchy::runtime::observatory::update_actor_snapshot;
    ///
    /// let result = update_actor_snapshot(());
    /// assert_eq!(result, Ok(()));
    /// ```
    pub fn update_actor_snapshot(&self, snapshot: ActorSnapshot) -> Result<()> {
        let mut snapshots = self
            .actor_snapshots
            .lock()
            .map_err(|_| anyhow::anyhow!("Failed to acquire actor snapshots lock"))?;
        snapshots.insert(snapshot.actor_id, snapshot);
        // Enforce snapshot limits
        if snapshots.len() > self.config.max_snapshots {
            // Remove oldest snapshots
            let mut oldest_actors: Vec<_> = snapshots
                .iter()
                .map(|(&id, snapshot)| (id, snapshot.timestamp))
                .collect();
            oldest_actors.sort_by_key(|(_, timestamp)| *timestamp);
            let to_remove = snapshots.len() - self.config.max_snapshots;
            for i in 0..to_remove {
                if let Some((actor_id, _)) = oldest_actors.get(i) {
                    snapshots.remove(actor_id);
                }
            }
        }
        Ok(())
    }
    /// Get current actor snapshots
    /// # Examples
    ///
    /// ```ignore
    /// use ruchy::runtime::observatory::get_actor_snapshots;
    ///
    /// let result = get_actor_snapshots(());
    /// assert_eq!(result, Ok(()));
    /// ```
    pub fn get_actor_snapshots(&self) -> Result<HashMap<ActorId, ActorSnapshot>> {
        Ok(self
            .actor_snapshots
            .lock()
            .map_err(|_| anyhow::anyhow!("Failed to acquire actor snapshots lock"))?
            .clone())
    }
    /// Get specific actor snapshot
    /// # Examples
    ///
    /// ```ignore
    /// use ruchy::runtime::observatory::get_actor_snapshot;
    ///
    /// let result = get_actor_snapshot(());
    /// assert_eq!(result, Ok(()));
    /// ```
    pub fn get_actor_snapshot(&self, actor_id: ActorId) -> Result<Option<ActorSnapshot>> {
        Ok(self
            .actor_snapshots
            .lock()
            .map_err(|_| anyhow::anyhow!("Failed to acquire actor snapshots lock"))?
            .get(&actor_id)
            .cloned())
    }
    /// Perform deadlock detection
    /// # Examples
    ///
    /// ```ignore
    /// use ruchy::runtime::observatory::detect_deadlocks;
    ///
    /// let result = detect_deadlocks(());
    /// assert_eq!(result, Ok(()));
    /// ```
    pub fn detect_deadlocks(&self) -> Result<Vec<DeadlockCycle>> {
        if !self.config.enable_deadlock_detection {
            return Ok(Vec::new());
        }
        let mut detector = self
            .deadlock_detector
            .lock()
            .map_err(|_| anyhow::anyhow!("Failed to acquire deadlock detector lock"))?;
        detector.detect_cycles()
    }
    /// Update system metrics
    /// # Examples
    ///
    /// ```ignore
    /// use ruchy::runtime::observatory::update_metrics;
    ///
    /// let result = update_metrics(());
    /// assert_eq!(result, Ok(()));
    /// ```
    pub fn update_metrics(&self) -> Result<()> {
        if !self.config.enable_metrics {
            return Ok(());
        }
        let _system = self
            .actor_system
            .lock()
            .map_err(|_| anyhow::anyhow!("Failed to acquire actor system lock"))?;
        let mut metrics = self
            .metrics
            .lock()
            .map_err(|_| anyhow::anyhow!("Failed to acquire metrics lock"))?;
        let snapshots = self
            .actor_snapshots
            .lock()
            .map_err(|_| anyhow::anyhow!("Failed to acquire actor snapshots lock"))?;
        // Update metrics based on current system state
        metrics.active_actors = snapshots.len();
        metrics.total_messages_processed = snapshots
            .values()
            .map(|s| s.message_stats.total_processed)
            .sum();
        metrics.total_queued_messages = snapshots.values().map(|s| s.mailbox_size).sum();
        metrics.avg_mailbox_size = if snapshots.is_empty() {
            0.0
        } else {
            metrics.total_queued_messages as f64 / snapshots.len() as f64
        };
        metrics.total_memory_usage = snapshots.values().filter_map(|s| s.memory_usage).sum();
        metrics.last_updated = current_timestamp();
        Ok(())
    }
    /// Get current system metrics
    /// # Examples
    ///
    /// ```ignore
    /// use ruchy::runtime::observatory::get_metrics;
    ///
    /// let result = get_metrics(());
    /// assert_eq!(result, Ok(()));
    /// ```
    pub fn get_metrics(&self) -> Result<SystemMetrics> {
        Ok(self
            .metrics
            .lock()
            .map_err(|_| anyhow::anyhow!("Failed to acquire metrics lock"))?
            .clone())
    }
    /// Get observatory uptime
    /// # Examples
    ///
    /// ```ignore
    /// use ruchy::runtime::observatory::uptime;
    ///
    /// let result = uptime(());
    /// assert_eq!(result, Ok(()));
    /// ```
    pub fn uptime(&self) -> Duration {
        self.start_time.elapsed()
    }
    /// Check if a message matches the configured filters
    fn message_matches_filters(&self, trace: &MessageTrace) -> bool {
        if self.filters.is_empty() {
            return true; // No filters means include all messages
        }
        self.filters
            .iter()
            .any(|filter| self.message_matches_filter(trace, filter))
    }
    /// Check if a message matches a specific filter
    fn message_matches_filter(&self, trace: &MessageTrace, filter: &MessageFilter) -> bool {
        // Filter by actor ID
        if let Some(filter_actor_id) = filter.actor_id {
            if trace.destination != filter_actor_id {
                return false;
            }
        }
        // Filter by processing time
        if let Some(min_time) = filter.min_processing_time_us {
            if let Some(duration) = trace.processing_duration_us {
                if duration < min_time {
                    return false;
                }
            } else {
                return false;
            }
        }
        // Filter by failed messages only
        if filter.failed_only && trace.status != MessageStatus::Failed {
            return false;
        }
        // Filter by stack depth
        if let Some(max_depth) = filter.max_stack_depth {
            if trace.stack_depth > max_depth {
                return false;
            }
        }
        true
    }
    /// Check if a trace matches a filter by name
    fn trace_matches_filter(&self, trace: &MessageTrace, filter_name: &str) -> bool {
        self.filters
            .iter()
            .find(|f| f.name == filter_name)
            .is_some_and(|filter| self.message_matches_filter(trace, filter))
    }
}
impl Default for DeadlockDetector {
    fn default() -> Self {
        Self::new()
    }
}
impl DeadlockDetector {
    /// Create a new deadlock detector
    pub fn new() -> Self {
        Self {
            dependency_graph: HashMap::new(),
            blocked_actors: HashMap::new(),
            last_check: Instant::now(),
            detected_deadlocks: Vec::new(),
        }
    }
    /// Add a blocked request to track
    /// # Examples
    ///
    /// ```ignore
    /// use ruchy::runtime::observatory::add_blocked_request;
    ///
    /// let result = add_blocked_request(());
    /// assert_eq!(result, Ok(()));
    /// ```
    pub fn add_blocked_request(&mut self, request: BlockedRequest) {
        self.blocked_actors
            .entry(request.requester)
            .or_default()
            .push(request.clone());
        // Update dependency graph
        self.dependency_graph
            .entry(request.requester)
            .or_default()
            .insert(request.target);
    }
    /// Remove a blocked request (when resolved)
    /// # Examples
    ///
    /// ```ignore
    /// use ruchy::runtime::observatory::remove_blocked_request;
    ///
    /// let result = remove_blocked_request(());
    /// assert_eq!(result, Ok(()));
    /// ```
    pub fn remove_blocked_request(&mut self, requester: ActorId, target: ActorId) {
        if let Some(requests) = self.blocked_actors.get_mut(&requester) {
            requests.retain(|r| r.target != target);
            if requests.is_empty() {
                self.blocked_actors.remove(&requester);
            }
        }
        // Update dependency graph
        if let Some(dependencies) = self.dependency_graph.get_mut(&requester) {
            dependencies.remove(&target);
            if dependencies.is_empty() {
                self.dependency_graph.remove(&requester);
            }
        }
    }
    /// Detect cycles in the dependency graph (potential deadlocks)
    /// # Examples
    ///
    /// ```ignore
    /// use ruchy::runtime::observatory::detect_cycles;
    ///
    /// let result = detect_cycles(());
    /// assert_eq!(result, Ok(()));
    /// ```
    pub fn detect_cycles(&mut self) -> Result<Vec<DeadlockCycle>> {
        let mut cycles = Vec::new();
        let mut visited = HashSet::new();
        let mut path = Vec::new();
        for &actor in self.dependency_graph.keys() {
            if !visited.contains(&actor) {
                self.dfs_detect_cycle(actor, &mut visited, &mut path, &mut cycles)?;
            }
        }
        self.detected_deadlocks.extend(cycles.clone());
        self.last_check = Instant::now();
        Ok(cycles)
    }
    /// Depth-first search to detect cycles
    fn dfs_detect_cycle(
        &self,
        actor: ActorId,
        visited: &mut HashSet<ActorId>,
        path: &mut Vec<ActorId>,
        cycles: &mut Vec<DeadlockCycle>,
    ) -> Result<()> {
        visited.insert(actor);
        path.push(actor);
        if let Some(dependencies) = self.dependency_graph.get(&actor) {
            for &dependent_actor in dependencies {
                if let Some(cycle_start_index) = path.iter().position(|&a| a == dependent_actor) {
                    // Found a cycle
                    let cycle_actors = path[cycle_start_index..].to_vec();
                    let duration_estimate = self.estimate_cycle_duration(&cycle_actors);
                    cycles.push(DeadlockCycle {
                        actors: cycle_actors.clone(),
                        detected_at: current_timestamp(),
                        duration_estimate_ms: duration_estimate,
                        resolution_suggestion: self.suggest_resolution(&cycle_actors),
                    });
                } else if !visited.contains(&dependent_actor) {
                    self.dfs_detect_cycle(dependent_actor, visited, path, cycles)?;
                }
            }
        }
        path.pop();
        Ok(())
    }
    /// Estimate how long a deadlock cycle has been active
    fn estimate_cycle_duration(&self, actors: &[ActorId]) -> u64 {
        let now = Instant::now();
        actors
            .iter()
            .filter_map(|&actor| self.blocked_actors.get(&actor))
            .flatten()
            .map(|request| now.duration_since(request.timestamp).as_millis() as u64)
            .max()
            .unwrap_or(0)
    }
    /// Suggest a resolution strategy for a deadlock cycle
    fn suggest_resolution(&self, actors: &[ActorId]) -> String {
        match actors.len() {
            1 => "Self-deadlock: Check for recursive message sending".to_string(),
            2 => "Binary deadlock: Consider using ask with timeout or redesign interaction pattern".to_string(),
            3..=5 => "Multi-actor deadlock: Implement hierarchical message ordering or use supervision".to_string(),
            _ => "Complex deadlock: Consider breaking into smaller subsystems or using event sourcing".to_string(),
        }
    }
}
/// Get current timestamp in seconds since Unix epoch
fn current_timestamp() -> u64 {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap_or_default()
        .as_secs()
}
/// Create a simple message filter for testing
impl MessageFilter {
    pub fn new(name: &str) -> Self {
        Self {
            name: name.to_string(),
            actor_id: None,
            actor_name_pattern: None,
            message_type_pattern: None,
            min_processing_time_us: None,
            failed_only: false,
            max_stack_depth: None,
        }
    }
    /// Create a filter for a specific actor
    /// # Examples
    ///
    /// ```ignore
    /// use ruchy::runtime::observatory::for_actor;
    ///
    /// let result = for_actor("example");
    /// assert_eq!(result, Ok(()));
    /// ```
    pub fn for_actor(name: &str, actor_id: ActorId) -> Self {
        Self {
            name: name.to_string(),
            actor_id: Some(actor_id),
            actor_name_pattern: None,
            message_type_pattern: None,
            min_processing_time_us: None,
            failed_only: false,
            max_stack_depth: None,
        }
    }
    /// Create a filter for failed messages only
    /// # Examples
    ///
    /// ```ignore
    /// use ruchy::runtime::observatory::failed_messages_only;
    ///
    /// let result = failed_messages_only("example");
    /// assert_eq!(result, Ok(()));
    /// ```
    pub fn failed_messages_only(name: &str) -> Self {
        Self {
            name: name.to_string(),
            actor_id: None,
            actor_name_pattern: None,
            message_type_pattern: None,
            min_processing_time_us: None,
            failed_only: true,
            max_stack_depth: None,
        }
    }
    /// Create a filter for delayed messages
    /// # Examples
    ///
    /// ```ignore
    /// use ruchy::runtime::observatory::slow_messages;
    ///
    /// let result = slow_messages("example");
    /// assert_eq!(result, Ok(()));
    /// ```
    pub fn slow_messages(name: &str, min_time_us: u64) -> Self {
        Self {
            name: name.to_string(),
            actor_id: None,
            actor_name_pattern: None,
            message_type_pattern: None,
            min_processing_time_us: Some(min_time_us),
            failed_only: false,
            max_stack_depth: None,
        }
    }
}
#[cfg(test)]
mod property_tests_observatory {
    use proptest::proptest;

    proptest! {
        /// Property: Function never panics on any input
        #[test]
        fn test_new_never_panics(input: String) {
            // Limit input size to avoid timeout
            let _input = if input.len() > 100 { &input[..100] } else { &input[..] };
            // Function should not panic on any input
            let _ = std::panic::catch_unwind(|| {
                // Call function with various inputs
                // This is a template - adjust based on actual function signature
            });
        }
    }
}
