use crate::event::{Event, EventPriority};
use std::collections::BinaryHeap;
use std::cmp::Ordering;
use std::sync::Arc;
use tokio::sync::RwLock;
use chrono::{DateTime, Utc};
use tracing::{debug, warn};

/// Wrapper for Event with priority queue ordering
#[derive(Clone)]
struct ScheduledEvent {
    event: Event,
    priority: EventPriority,
    scheduled_at: DateTime<Utc>,
}

impl PartialEq for ScheduledEvent {
    fn eq(&self, other: &Self) -> bool {
        self.scheduled_at == other.scheduled_at && self.priority == other.priority
    }
}

impl Eq for ScheduledEvent {}

impl PartialOrd for ScheduledEvent {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for ScheduledEvent {
    fn cmp(&self, other: &Self) -> Ordering {
        // First compare by scheduled time (earlier = higher priority)
        match self.scheduled_at.cmp(&other.scheduled_at) {
            Ordering::Equal => {
                // Then by priority (higher = higher priority)
                other.priority.cmp(&self.priority)
            }
            other => other,
        }
    }
}

/// Event scheduler for delayed and prioritized events
pub struct EventScheduler {
    /// Priority queue of scheduled events
    queue: Arc<RwLock<BinaryHeap<ScheduledEvent>>>,
}

impl EventScheduler {
    pub fn new() -> Self {
        Self {
            queue: Arc::new(RwLock::new(BinaryHeap::new())),
        }
    }
    
    /// Schedule an event for future execution
    pub async fn schedule(&self, event: Event, scheduled_at: DateTime<Utc>) {
        let priority = event.priority;
        let scheduled = ScheduledEvent {
            event,
            priority,
            scheduled_at,
        };
        
        let mut queue = self.queue.write().await;
        queue.push(scheduled);
        debug!("Scheduled event for {:?}", scheduled_at);
    }
    
    /// Schedule an event with a delay (seconds)
    pub async fn schedule_delayed(&self, event: Event, delay_seconds: u64) {
        let scheduled_at = Utc::now() + chrono::Duration::seconds(delay_seconds as i64);
        self.schedule(event, scheduled_at).await;
    }
    
    /// Get all ready events (scheduled time <= now)
    pub async fn get_ready_events(&self) -> Vec<Event> {
        let mut queue = self.queue.write().await;
        let mut ready = Vec::new();
        let now = Utc::now();
        
        // Collect all ready events
        let mut temp_queue = BinaryHeap::new();
        while let Some(scheduled) = queue.pop() {
            if scheduled.scheduled_at <= now {
                ready.push(scheduled.event);
            } else {
                temp_queue.push(scheduled);
            }
        }
        
        // Put back events that aren't ready yet
        *queue = temp_queue;
        
        debug!("Retrieved {} ready events from scheduler", ready.len());
        ready
    }
    
    /// Get the next scheduled event time (for polling)
    pub async fn next_scheduled_time(&self) -> Option<DateTime<Utc>> {
        let queue = self.queue.read().await;
        queue.peek().map(|scheduled| scheduled.scheduled_at)
    }
    
    /// Get queue size
    pub async fn queue_size(&self) -> usize {
        let queue = self.queue.read().await;
        queue.len()
    }
    
    /// Clear all scheduled events
    pub async fn clear(&self) {
        let mut queue = self.queue.write().await;
        queue.clear();
        warn!("Cleared all scheduled events");
    }
}

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

