//! Refactored Event Processor with Repository Pattern
//!
//! This module provides the same high-performance event processing capabilities
//! but with clean separation of concerns using dependency injection.

use anyhow::{anyhow, Result};
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::Arc;
use std::time::Duration;
use tokio::time::sleep;

// Import timing infrastructure
use crate::timing::HardwareTimestamp;

// Import repository abstractions
use crate::repositories::{EventRepository, EventRepositoryError};

// Re-export types for convenience
use super::{
    BufferManager, BufferStats, EventLevel, EventMetadata, EventMetricsSnapshot, 
    EventSequence, TradingEvent, WriterConfig
};

/// Configuration for the refactored event processing pipeline
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
/// EventProcessorConfig
/// 
/// Auto-generated documentation placeholder - enhance with specifics
pub struct EventProcessorConfig {
    /// Number of ring buffers for load balancing
    pub buffer_count: usize,
    /// Size of each ring buffer (must be power of 2)
    pub buffer_size: usize,
    /// Maximum batch size for database inserts
    pub batch_size: usize,
    /// Batch timeout in milliseconds
    pub batch_timeout_ms: u64,
    /// Number of writer threads
    pub writer_threads: usize,
    /// Enable compression for large events
    pub enable_compression: bool,
    /// Maximum memory usage before applying backpressure (bytes)
    pub max_memory_usage: usize,
    /// Enable detailed monitoring
    pub enable_monitoring: bool,
    /// Retry attempts for failed writes
    pub max_retry_attempts: usize,
    /// Retry delay base in milliseconds
    pub retry_delay_ms: u64,
}

impl Default for EventProcessorConfig {
    fn default() -> Self {
        Self {
            buffer_count: num_cpus::get().max(4),
            buffer_size: 8192, // 8K events per buffer
            batch_size: 1000,
            batch_timeout_ms: 10,
            writer_threads: 2,
            enable_compression: true,
            max_memory_usage: 100 * 1024 * 1024, // 100MB
            enable_monitoring: true,
            max_retry_attempts: 3,
            retry_delay_ms: 100,
        }
    }
}

/// Repository-injected high-performance event processor
pub struct EventProcessor {
    /// Configuration
    config: EventProcessorConfig,
    /// Buffer manager for load balancing across multiple ring buffers
    buffer_manager: Arc<BufferManager>,
    /// Event repository abstraction (injected dependency)
    event_repository: Arc<dyn EventRepository>,
    /// Async writer pool
    writers: Vec<Arc<RepositoryBackedWriter>>,
    /// Global sequence number generator
    sequence_generator: Arc<AtomicU64>,
    /// Shutdown signal
    shutdown: Arc<AtomicBool>,
    /// Performance monitoring
    metrics: Arc<EventMetrics>,
    /// Health monitor
    health_monitor: Arc<HealthMonitor>,
}

impl EventProcessor {
    /// Create a new event processor with injected repository dependency
    pub async fn new(
        config: EventProcessorConfig,
        event_repository: Arc<dyn EventRepository>,
    ) -> Result<Self> {
        tracing::info!("Initializing event processor with config: {:?}", config);

        // Initialize database schema through repository
        event_repository
            .initialize_schema()
            .await
            .map_err(|e| anyhow!("Failed to initialize schema: {}", e))?;

        // Create buffer manager
        let buffer_manager = Arc::new(BufferManager::new(config.buffer_count, config.buffer_size)?);

        // Create metrics and monitoring
        let metrics = Arc::new(EventMetrics::new());
        let health_monitor = Arc::new(HealthMonitor::new());

        // Create repository-backed writers
        let mut writers = Vec::with_capacity(config.writer_threads);
        for i in 0..config.writer_threads {
            let writer_config = WriterConfig {
                batch_size: config.batch_size,
                batch_timeout: Duration::from_millis(config.batch_timeout_ms),
                max_retry_attempts: config.max_retry_attempts,
                retry_delay: Duration::from_millis(config.retry_delay_ms),
                enable_compression: config.enable_compression,
                thread_id: i,
            };

            let writer = Arc::new(
                RepositoryBackedWriter::new(
                    writer_config,
                    event_repository.clone(),
                    metrics.clone(),
                ).await?,
            );

            writers.push(writer);
        }

        let processor = Self {
            config,
            buffer_manager,
            event_repository,
            writers,
            sequence_generator: Arc::new(AtomicU64::new(1)),
            shutdown: Arc::new(AtomicBool::new(false)),
            metrics,
            health_monitor,
        };

        // Start background processing tasks
        processor.start_background_tasks().await?;

        tracing::info!("Event processor initialized successfully");
    // Ok variant
        Ok(processor)
    }

    /// Capture a trading event with sub-microsecond latency
    #[inline(always)]
    pub async fn capture_event(&self, mut event: TradingEvent) -> Result<EventSequence> {
        let start_time = HardwareTimestamp::now();

        // Generate global sequence number
        let sequence_number = self.sequence_generator.fetch_add(1, Ordering::Relaxed);

        // Add metadata
        event.set_sequence_number(sequence_number);
        event.set_capture_timestamp(start_time);

        // Find optimal buffer (load balancing)
        let buffer_index = self.buffer_manager.select_buffer();

        // Attempt to store in ring buffer (lock-free)
        let result = self.buffer_manager.try_push(buffer_index, event).await;

        // Update metrics
        let capture_latency = HardwareTimestamp::now().latency_ns(&start_time);
        self.metrics.record_capture_latency(capture_latency);

        match result {
            Ok(seq) => {
                self.metrics.increment_events_captured();
    // Ok variant
                Ok(seq)
            }
            Err(e) => {
                self.metrics.increment_events_dropped();
                Err(anyhow!("Failed to capture event: {}", e))
            }
        }
    }

    /// Start background processing tasks
    async fn start_background_tasks(&self) -> Result<()> {
        let shutdown = self.shutdown.clone();
        let buffer_manager = self.buffer_manager.clone();
        let writers = self.writers.clone();
        let metrics = self.metrics.clone();

        // Start buffer-to-writer routing task
        tokio::spawn(async move {
            Self::buffer_router_task(shutdown, buffer_manager, writers, metrics).await;
        });

        // Start health monitoring task
        let shutdown_monitor = self.shutdown.clone();
        let health_monitor_clone = self.health_monitor.clone();
        let metrics_clone = self.metrics.clone();
        tokio::spawn(async move {
            Self::health_monitor_task(shutdown_monitor, health_monitor_clone, metrics_clone).await;
        });

        // Start metrics reporting task
        let shutdown_metrics = self.shutdown.clone();
        let metrics_reporting = self.metrics.clone();
        let repository_metrics = self.event_repository.clone();
        tokio::spawn(async move {
            Self::metrics_reporting_task(shutdown_metrics, metrics_reporting, repository_metrics)
                .await;
        });

        Ok(())
    }

    /// Background task to route events from buffers to writers
    async fn buffer_router_task(
        shutdown: Arc<AtomicBool>,
        buffer_manager: Arc<BufferManager>,
        writers: Vec<Arc<RepositoryBackedWriter>>,
        metrics: Arc<EventMetrics>,
    ) {
        let mut writer_index = 0;

        while !shutdown.load(Ordering::Relaxed) {
            let mut events_routed = 0;

            // Check all buffers for events
            for buffer_id in 0..buffer_manager.buffer_count() {
                if let Some(events) = buffer_manager.drain_buffer(buffer_id, 100).await {
                    if !events.is_empty() {
                        // Round-robin distribution to writers
                        let writer = &writers[writer_index % writers.len()];

                        // Send batch to writer
                        if let Err(e) = writer.submit_batch(events).await {
                            tracing::error!(
                                "Failed to submit batch to writer {}: {}",
                                writer_index,
                                e
                            );
                            metrics.increment_routing_errors();
                        } else {
                            events_routed += 1;
                        }

                        writer_index = (writer_index + 1) % writers.len();
                    }
                }
            }

            // Short sleep to prevent busy waiting
            if events_routed == 0 {
                sleep(Duration::from_micros(100)).await;
            }
        }
    }

    /// Background health monitoring task
    async fn health_monitor_task(
        shutdown: Arc<AtomicBool>,
        health_monitor: Arc<HealthMonitor>,
        metrics: Arc<EventMetrics>,
    ) {
        while !shutdown.load(Ordering::Relaxed) {
            // Update health status
            health_monitor.update_health(metrics.get_snapshot()).await;

            // Sleep for 1 second between health checks
            sleep(Duration::from_secs(1)).await;
        }
    }

    /// Background metrics reporting task using repository
    async fn metrics_reporting_task(
        shutdown: Arc<AtomicBool>,
        metrics: Arc<EventMetrics>,
        repository: Arc<dyn EventRepository>,
    ) {
        while !shutdown.load(Ordering::Relaxed) {
            // Log metrics to database through repository every 30 seconds
            let snapshot = metrics.get_snapshot();
            if let Err(e) = repository.store_processing_metrics(snapshot).await {
                tracing::error!("Failed to persist metrics through repository: {}", e);
            }

            sleep(Duration::from_secs(30)).await;
        }
    }

    /// Get current performance metrics
    pub fn get_metrics(&self) -> EventMetricsSnapshot {
        self.metrics.get_snapshot()
    }

    /// Get health status
    pub async fn get_health(&self) -> HealthStatus {
        self.health_monitor.get_status().await
    }

    /// Get buffer statistics
    pub async fn get_buffer_stats(&self) -> Vec<BufferStats> {
        self.buffer_manager.get_all_stats().await
    }

    /// Graceful shutdown
    pub async fn shutdown(&self) -> Result<()> {
        tracing::info!("Initiating graceful shutdown");

        // Set shutdown flag
        self.shutdown.store(true, Ordering::Relaxed);

        // Wait for writers to finish processing
        for writer in &self.writers {
            writer.shutdown().await?;
        }

        // Drain remaining buffers
        self.buffer_manager.drain_all_buffers().await?;

        tracing::info!("Event processor shutdown complete");
        Ok(())
    }
}

/// Repository-backed writer that uses EventRepository abstraction
pub struct RepositoryBackedWriter {
    config: WriterConfig,
    repository: Arc<dyn EventRepository>,
    metrics: Arc<EventMetrics>,
    shutdown: Arc<AtomicBool>,
    batch_queue: Arc<tokio::sync::Mutex<Vec<TradingEvent>>>,
}

impl RepositoryBackedWriter {
    pub async fn new(
        config: WriterConfig,
        repository: Arc<dyn EventRepository>,
        metrics: Arc<EventMetrics>,
    ) -> Result<Self> {
        Ok(Self {
            config,
            repository,
            metrics,
            shutdown: Arc::new(AtomicBool::new(false)),
            batch_queue: Arc::new(tokio::sync::Mutex::new(Vec::new())),
        })
    }

    pub async fn submit_batch(&self, events: Vec<TradingEvent>) -> Result<()> {
        if self.shutdown.load(Ordering::Relaxed) {
            return Err(anyhow!("Writer is shutting down"));
        }

        let start_time = std::time::Instant::now();

        // Create batch using repository abstraction
        let batch = crate::repositories::EventBatch::new(events);
        
        // Submit to repository
        match self.repository.persist_event_batch(batch).await {
            Ok(()) => {
                let write_latency = start_time.elapsed().as_millis() as f64;
                self.metrics.record_write_latency(write_latency);
                self.metrics.increment_events_written(1); // Simplified for this example
                Ok(())
            }
            Err(e) => {
                self.metrics.increment_failed_writes();
                tracing::error!("Failed to persist batch: {}", e);
                Err(anyhow!("Repository error: {}", e))
            }
        }
    }

    pub async fn shutdown(&self) -> Result<()> {
        self.shutdown.store(true, Ordering::Relaxed);
        
        // Flush any remaining events
        let remaining_events = {
            let mut queue = self.batch_queue.lock().await;
            std::mem::take(&mut *queue)
        };

        if !remaining_events.is_empty() {
            let batch = crate::repositories::EventBatch::new(remaining_events);
            if let Err(e) = self.repository.persist_event_batch(batch).await {
                tracing::error!("Failed to flush remaining events during shutdown: {}", e);
            }
        }

        Ok(())
    }
}

// Removed pub use - import EventMetrics, HealthMonitor, HealthStatus directly where needed

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

    #[tokio::test]
    async fn test_refactored_event_processor_creation() -> Result<()> {
        let config = EventProcessorConfig {
            buffer_count: 2,
            buffer_size: 64,
            batch_size: 10,
            ..Default::default()
        };

        let mock_repository = Arc::new(MockEventRepository::new());
        
        // This should now work without requiring a real database
        let _processor = EventProcessor::new(config, mock_repository).await?;
        
        Ok(())
    }

    #[tokio::test]
    async fn test_repository_backed_writer() -> Result<()> {
        let config = WriterConfig {
            batch_size: 10,
            batch_timeout: Duration::from_millis(100),
            max_retry_attempts: 3,
            retry_delay: Duration::from_millis(50),
            enable_compression: false,
            thread_id: 0,
        };

        let mock_repository = Arc::new(MockEventRepository::new());
        let metrics = Arc::new(EventMetrics::new());

        let writer = RepositoryBackedWriter::new(config, mock_repository.clone(), metrics).await?;
        
        // Test batch submission
        let events = vec![]; // Would contain actual TradingEvent instances
        writer.submit_batch(events).await?;
        
        Ok(())
    }
}