//! Event system for SciRS2 integration
//!
//! This module defines all event types, contexts, and event processing
//! functionality for real-time monitoring and optimization.

use super::{
    config::{CleanupStatus, FragmentationType, PressureTrend, UtilizationChangeReason},
    pool_management::ScirS2PoolInfo,
    statistics::{AllocationUsageStats, MemoryStateSnapshot, PerformanceSnapshot},
};
use crate::memory_profiler::allocation::PressureLevel;
use std::collections::HashMap;
use std::time::{Duration, Instant};

/// SciRS2 memory events
///
/// Events generated by SciRS2 allocators and memory management systems
/// for real-time monitoring and optimization.
#[derive(Debug, Clone)]
pub enum ScirS2Event {
    /// New memory allocation
    Allocation {
        ptr: *mut u8,
        size: usize,
        allocator: String,
        allocation_context: AllocationEventContext,
    },

    /// Memory deallocation
    Deallocation {
        ptr: *mut u8,
        allocator: String,
        deallocation_context: DeallocationEventContext,
    },

    /// Memory pool created
    PoolCreated {
        pool_id: String,
        capacity: usize,
        pool_type: String,
        creation_context: PoolCreationContext,
    },

    /// Memory pool destroyed
    PoolDestroyed {
        pool_id: String,
        destruction_context: PoolDestructionContext,
    },

    /// Memory pressure event
    MemoryPressure {
        level: PressureLevel,
        available_memory: usize,
        pressure_context: MemoryPressureContext,
    },

    /// Performance optimization suggestion
    OptimizationSuggestion {
        suggestion_type: String,
        impact_estimate: f64,
        suggested_action: String,
        optimization_context: OptimizationContext,
    },

    /// Pool utilization change
    PoolUtilizationChange {
        pool_id: String,
        old_utilization: f64,
        new_utilization: f64,
        change_reason: UtilizationChangeReason,
    },

    /// Allocator performance degradation
    PerformanceDegradation {
        allocator: String,
        metric: String,
        degradation_amount: f64,
        threshold_exceeded: bool,
    },

    /// Fragmentation event
    FragmentationEvent {
        allocator: String,
        fragmentation_level: f64,
        fragmentation_type: FragmentationType,
        mitigation_suggested: bool,
    },
}

/// Allocation event context
#[derive(Debug, Clone)]
pub struct AllocationEventContext {
    /// Thread ID
    pub thread_id: u64,

    /// Allocation reason
    pub reason: String,

    /// Performance metrics at allocation time
    pub performance_snapshot: PerformanceSnapshot,

    /// Memory state snapshot
    pub memory_snapshot: MemoryStateSnapshot,
}

/// Deallocation event context
#[derive(Debug, Clone)]
pub struct DeallocationEventContext {
    /// Thread ID
    pub thread_id: u64,

    /// Allocation lifetime
    pub allocation_lifetime: Duration,

    /// Usage statistics
    pub usage_stats: AllocationUsageStats,
}

/// Pool creation context
#[derive(Debug, Clone)]
pub struct PoolCreationContext {
    /// Reason for creation
    pub creation_reason: String,

    /// Initial configuration
    pub initial_config: HashMap<String, String>,

    /// Expected usage pattern
    pub expected_usage: String,
}

/// Pool destruction context
#[derive(Debug, Clone)]
pub struct PoolDestructionContext {
    /// Reason for destruction
    pub destruction_reason: String,

    /// Final statistics
    pub final_stats: ScirS2PoolInfo,

    /// Cleanup status
    pub cleanup_status: CleanupStatus,
}

/// Memory pressure context
#[derive(Debug, Clone)]
pub struct MemoryPressureContext {
    /// System-wide memory usage
    pub system_memory_usage: usize,

    /// SciRS2-specific memory usage
    pub scirs2_memory_usage: usize,

    /// Active allocators
    pub active_allocators: Vec<String>,

    /// Pressure trend
    pub pressure_trend: PressureTrend,
}

/// Optimization context
#[derive(Debug, Clone)]
pub struct OptimizationContext {
    /// Target component
    pub target_component: String,

    /// Current performance baseline
    pub performance_baseline: PerformanceSnapshot,

    /// Optimization confidence
    pub confidence: f64,

    /// Prerequisites
    pub prerequisites: Vec<String>,
}

/// Event processor for handling SciRS2 events
pub struct ScirS2EventProcessor {
    /// Event callbacks
    callbacks: Vec<Box<dyn Fn(&ScirS2Event) + Send + Sync>>,

    /// Event statistics
    event_stats: EventStatistics,

    /// Event filters
    filters: Vec<EventFilter>,

    /// Event buffer for batch processing
    event_buffer: Vec<ScirS2Event>,

    /// Buffer size limit
    buffer_limit: usize,
}

/// Event processing statistics
#[derive(Debug, Clone)]
pub struct EventStatistics {
    /// Total events processed
    pub total_events: u64,

    /// Events by type
    pub events_by_type: HashMap<String, u64>,

    /// Processing times
    pub processing_times: Vec<Duration>,

    /// Average processing time
    pub avg_processing_time: Duration,

    /// Event rate (events per second)
    pub event_rate: f64,

    /// Last processing time
    pub last_processing_time: Instant,
}

/// Event filter for selective event processing
#[derive(Debug, Clone)]
pub struct EventFilter {
    /// Filter name
    pub name: String,

    /// Event types to include (empty means all)
    pub include_types: Vec<String>,

    /// Event types to exclude
    pub exclude_types: Vec<String>,

    /// Minimum severity level
    pub min_severity: EventSeverity,

    /// Custom filter predicate
    pub custom_filter: Option<String>, // Simplified - would be a proper predicate in real implementation
}

/// Event severity levels
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum EventSeverity {
    Debug,
    Info,
    Warning,
    Error,
    Critical,
}

impl ScirS2EventProcessor {
    /// Create new event processor
    pub fn new() -> Self {
        Self {
            callbacks: Vec::new(),
            event_stats: EventStatistics::new(),
            filters: Vec::new(),
            event_buffer: Vec::new(),
            buffer_limit: 1000,
        }
    }

    /// Add event callback
    pub fn add_callback<F>(&mut self, callback: F)
    where
        F: Fn(&ScirS2Event) + Send + Sync + 'static,
    {
        self.callbacks.push(Box::new(callback));
    }

    /// Add event filter
    pub fn add_filter(&mut self, filter: EventFilter) {
        self.filters.push(filter);
    }

    /// Process a single event
    pub fn process_event(&mut self, event: ScirS2Event) {
        let start_time = Instant::now();

        // Check if event passes filters
        if !self.event_passes_filters(&event) {
            return;
        }

        // Update statistics
        self.event_stats.record_event(&event, start_time);

        // Add to buffer for batch processing
        self.event_buffer.push(event.clone());

        // Process buffer if it's full
        if self.event_buffer.len() >= self.buffer_limit {
            self.process_buffer();
        }

        // Call event callbacks
        for callback in &self.callbacks {
            callback(&event);
        }

        // Record processing time
        let processing_time = start_time.elapsed();
        self.event_stats.processing_times.push(processing_time);

        // Keep only last 1000 processing times
        if self.event_stats.processing_times.len() > 1000 {
            self.event_stats.processing_times.remove(0);
        }

        // Update average processing time
        self.event_stats.update_avg_processing_time();
    }

    /// Process events in batch
    pub fn process_buffer(&mut self) {
        if self.event_buffer.is_empty() {
            return;
        }

        // Batch processing logic
        let allocation_events: Vec<_> = self
            .event_buffer
            .iter()
            .filter_map(|e| match e {
                ScirS2Event::Allocation { .. } => Some(e),
                _ => None,
            })
            .collect();

        let deallocation_events: Vec<_> = self
            .event_buffer
            .iter()
            .filter_map(|e| match e {
                ScirS2Event::Deallocation { .. } => Some(e),
                _ => None,
            })
            .collect();

        // Process allocation/deallocation pairs for lifecycle analysis
        self.analyze_allocation_lifecycle(&allocation_events, &deallocation_events);

        // Process memory pressure events for trend analysis
        let pressure_events: Vec<_> = self
            .event_buffer
            .iter()
            .filter_map(|e| match e {
                ScirS2Event::MemoryPressure { .. } => Some(e),
                _ => None,
            })
            .collect();

        if !pressure_events.is_empty() {
            self.analyze_pressure_trends(&pressure_events);
        }

        // Clear buffer
        self.event_buffer.clear();
    }

    /// Get event processing statistics
    pub fn get_statistics(&self) -> &EventStatistics {
        &self.event_stats
    }

    /// Set buffer limit
    pub fn set_buffer_limit(&mut self, limit: usize) {
        self.buffer_limit = limit;
    }

    /// Get event severity
    pub fn get_event_severity(&self, event: &ScirS2Event) -> EventSeverity {
        match event {
            ScirS2Event::Allocation { .. } => EventSeverity::Debug,
            ScirS2Event::Deallocation { .. } => EventSeverity::Debug,
            ScirS2Event::PoolCreated { .. } => EventSeverity::Info,
            ScirS2Event::PoolDestroyed { .. } => EventSeverity::Info,
            ScirS2Event::MemoryPressure { level, .. } => match level {
                PressureLevel::None => EventSeverity::Debug,
                PressureLevel::Low => EventSeverity::Info,
                PressureLevel::Medium => EventSeverity::Warning,
                PressureLevel::High => EventSeverity::Error,
                PressureLevel::Critical => EventSeverity::Critical,
            },
            ScirS2Event::OptimizationSuggestion { .. } => EventSeverity::Info,
            ScirS2Event::PoolUtilizationChange { .. } => EventSeverity::Info,
            ScirS2Event::PerformanceDegradation {
                threshold_exceeded, ..
            } => {
                if *threshold_exceeded {
                    EventSeverity::Warning
                } else {
                    EventSeverity::Info
                }
            }
            ScirS2Event::FragmentationEvent {
                fragmentation_level,
                ..
            } => {
                if *fragmentation_level > 0.5 {
                    EventSeverity::Warning
                } else {
                    EventSeverity::Info
                }
            }
        }
    }

    /// Clear event statistics
    pub fn clear_statistics(&mut self) {
        self.event_stats = EventStatistics::new();
    }

    /// Force buffer processing
    pub fn flush_buffer(&mut self) {
        self.process_buffer();
    }

    // Private helper methods

    fn event_passes_filters(&self, event: &ScirS2Event) -> bool {
        if self.filters.is_empty() {
            return true;
        }

        for filter in &self.filters {
            if !self.event_matches_filter(event, filter) {
                return false;
            }
        }

        true
    }

    fn event_matches_filter(&self, event: &ScirS2Event, filter: &EventFilter) -> bool {
        let event_type = self.get_event_type_name(event);
        let event_severity = self.get_event_severity(event);

        // Check include types
        if !filter.include_types.is_empty() && !filter.include_types.contains(&event_type) {
            return false;
        }

        // Check exclude types
        if filter.exclude_types.contains(&event_type) {
            return false;
        }

        // Check severity
        if event_severity < filter.min_severity {
            return false;
        }

        true
    }

    fn get_event_type_name(&self, event: &ScirS2Event) -> String {
        match event {
            ScirS2Event::Allocation { .. } => "Allocation".to_string(),
            ScirS2Event::Deallocation { .. } => "Deallocation".to_string(),
            ScirS2Event::PoolCreated { .. } => "PoolCreated".to_string(),
            ScirS2Event::PoolDestroyed { .. } => "PoolDestroyed".to_string(),
            ScirS2Event::MemoryPressure { .. } => "MemoryPressure".to_string(),
            ScirS2Event::OptimizationSuggestion { .. } => "OptimizationSuggestion".to_string(),
            ScirS2Event::PoolUtilizationChange { .. } => "PoolUtilizationChange".to_string(),
            ScirS2Event::PerformanceDegradation { .. } => "PerformanceDegradation".to_string(),
            ScirS2Event::FragmentationEvent { .. } => "FragmentationEvent".to_string(),
        }
    }

    fn analyze_allocation_lifecycle(
        &self,
        _allocations: &[&ScirS2Event],
        _deallocations: &[&ScirS2Event],
    ) {
        // Simplified lifecycle analysis
        // In a real implementation, you'd match allocations with deallocations
        // and analyze patterns like allocation duration, usage patterns, etc.
    }

    fn analyze_pressure_trends(&self, _pressure_events: &[&ScirS2Event]) {
        // Simplified pressure trend analysis
        // In a real implementation, you'd analyze pressure level changes over time
        // and predict future pressure events
    }
}

impl EventStatistics {
    fn new() -> Self {
        Self {
            total_events: 0,
            events_by_type: HashMap::new(),
            processing_times: Vec::new(),
            avg_processing_time: Duration::from_secs(0),
            event_rate: 0.0,
            last_processing_time: Instant::now(),
        }
    }

    fn record_event(&mut self, event: &ScirS2Event, timestamp: Instant) {
        self.total_events += 1;

        // Update events by type
        let event_type = match event {
            ScirS2Event::Allocation { .. } => "Allocation",
            ScirS2Event::Deallocation { .. } => "Deallocation",
            ScirS2Event::PoolCreated { .. } => "PoolCreated",
            ScirS2Event::PoolDestroyed { .. } => "PoolDestroyed",
            ScirS2Event::MemoryPressure { .. } => "MemoryPressure",
            ScirS2Event::OptimizationSuggestion { .. } => "OptimizationSuggestion",
            ScirS2Event::PoolUtilizationChange { .. } => "PoolUtilizationChange",
            ScirS2Event::PerformanceDegradation { .. } => "PerformanceDegradation",
            ScirS2Event::FragmentationEvent { .. } => "FragmentationEvent",
        };

        *self
            .events_by_type
            .entry(event_type.to_string())
            .or_insert(0) += 1;

        // Update event rate
        let time_since_last = timestamp.duration_since(self.last_processing_time);
        if time_since_last.as_secs_f64() > 0.0 {
            self.event_rate = 1.0 / time_since_last.as_secs_f64();
        }

        self.last_processing_time = timestamp;
    }

    fn update_avg_processing_time(&mut self) {
        if !self.processing_times.is_empty() {
            let total: Duration = self.processing_times.iter().sum();
            self.avg_processing_time = total / self.processing_times.len() as u32;
        }
    }

    /// Get events per second over the last minute
    pub fn events_per_second(&self) -> f64 {
        // Simplified calculation - in a real implementation,
        // you'd track timestamps and calculate rate properly
        self.event_rate
    }

    /// Get most common event type
    pub fn most_common_event_type(&self) -> Option<String> {
        self.events_by_type
            .iter()
            .max_by_key(|(_, count)| *count)
            .map(|(event_type, _)| event_type.clone())
    }
}

impl EventFilter {
    /// Create a new event filter
    pub fn new(name: String) -> Self {
        Self {
            name,
            include_types: Vec::new(),
            exclude_types: Vec::new(),
            min_severity: EventSeverity::Debug,
            custom_filter: None,
        }
    }

    /// Create filter for allocation events only
    pub fn allocation_only() -> Self {
        Self {
            name: "Allocation Filter".to_string(),
            include_types: vec!["Allocation".to_string(), "Deallocation".to_string()],
            exclude_types: Vec::new(),
            min_severity: EventSeverity::Debug,
            custom_filter: None,
        }
    }

    /// Create filter for high-severity events only
    pub fn high_severity_only() -> Self {
        Self {
            name: "High Severity Filter".to_string(),
            include_types: Vec::new(),
            exclude_types: Vec::new(),
            min_severity: EventSeverity::Warning,
            custom_filter: None,
        }
    }

    /// Create filter for performance events
    pub fn performance_events() -> Self {
        Self {
            name: "Performance Filter".to_string(),
            include_types: vec![
                "PerformanceDegradation".to_string(),
                "OptimizationSuggestion".to_string(),
                "FragmentationEvent".to_string(),
            ],
            exclude_types: Vec::new(),
            min_severity: EventSeverity::Info,
            custom_filter: None,
        }
    }

    /// Add include type
    pub fn include_type(&mut self, event_type: String) {
        self.include_types.push(event_type);
    }

    /// Add exclude type
    pub fn exclude_type(&mut self, event_type: String) {
        self.exclude_types.push(event_type);
    }

    /// Set minimum severity
    pub fn set_min_severity(&mut self, severity: EventSeverity) {
        self.min_severity = severity;
    }
}

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