use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::Semaphore;
use tokio::task::JoinHandle;
use tracing::{debug, error, info, warn};
use uuid::Uuid;

/// Task for concurrent execution
#[derive(Debug, Clone)]
pub struct ConcurrentTask {
    pub id: Uuid,
    pub name: String,
    pub priority: u8, // Higher = more priority
}

/// Result of concurrent task execution
#[derive(Debug)]
pub struct ConcurrentTaskResult<T> {
    pub task_id: Uuid,
    pub success: bool,
    pub result: Option<T>,
    pub error: Option<String>,
    pub execution_time_ms: u64,
}

/// Premium concurrent executor for parallel task execution
/// 
/// Features:
/// - Worker pool with configurable concurrency limits
/// - Priority-based task scheduling
/// - Task cancellation support
/// - Timeout handling
/// - Deterministic execution order when needed
pub struct ConcurrentExecutor {
    /// Semaphore for controlling concurrency
    semaphore: Arc<Semaphore>,
    
    /// Maximum concurrent tasks
    max_concurrent: usize,
    
    /// Active task handles
    active_tasks: Arc<tokio::sync::RwLock<HashMap<Uuid, JoinHandle<()>>>>,
}

impl ConcurrentExecutor {
    /// Create a new concurrent executor
    pub fn new(max_concurrent: usize) -> Self {
        Self {
            semaphore: Arc::new(Semaphore::new(max_concurrent)),
            max_concurrent,
            active_tasks: Arc::new(tokio::sync::RwLock::new(HashMap::new())),
        }
    }
    
    /// Execute a task concurrently with resource limits
    pub async fn execute<F, T>(
        &self,
        task_id: Uuid,
        task_name: String,
        task: F,
    ) -> Result<T, String>
    where
        F: std::future::Future<Output = Result<T, String>> + Send + 'static,
        T: Send + 'static,
    {
        let permit = self.semaphore.clone().acquire_owned().await
            .map_err(|e| format!("Failed to acquire semaphore: {}", e))?;
        
        let start_time = std::time::Instant::now();
        
        info!("Executing concurrent task: {} ({})", task_name, task_id);
        
        // Spawn the task
        let task_handle = tokio::spawn(async move {
            let result = task.await;
            drop(permit); // Release semaphore when done
            result
        });
        
        // Store task handle
        {
            let mut tasks = self.active_tasks.write().await;
            tasks.insert(task_id, task_handle);
        }
        
        // Wait for completion
        let result = match task_handle.await {
            Ok(Ok(value)) => {
                let elapsed = start_time.elapsed().as_millis() as u64;
                info!("Task {} completed in {}ms", task_name, elapsed);
                Ok(value)
            }
            Ok(Err(e)) => {
                error!("Task {} failed: {}", task_name, e);
                Err(e)
            }
            Err(e) => {
                error!("Task {} panicked: {}", task_name, e);
                Err(format!("Task panicked: {}", e))
            }
        };
        
        // Remove from active tasks
        {
            let mut tasks = self.active_tasks.write().await;
            tasks.remove(&task_id);
        }
        
        result
    }
    
    /// Execute multiple tasks in parallel
    pub async fn execute_parallel<F, T>(
        &self,
        tasks: Vec<(Uuid, String, F)>,
    ) -> Vec<ConcurrentTaskResult<T>>
    where
        F: std::future::Future<Output = Result<T, String>> + Send + 'static,
        T: Send + 'static,
    {
        let mut handles = Vec::new();
        
        for (task_id, task_name, task) in tasks {
            let executor = self.clone();
            let handle = tokio::spawn(async move {
                let start_time = std::time::Instant::now();
                match executor.execute(task_id, task_name.clone(), task).await {
                    Ok(result) => ConcurrentTaskResult {
                        task_id,
                        success: true,
                        result: Some(result),
                        error: None,
                        execution_time_ms: start_time.elapsed().as_millis() as u64,
                    },
                    Err(e) => ConcurrentTaskResult {
                        task_id,
                        success: false,
                        result: None,
                        error: Some(e),
                        execution_time_ms: start_time.elapsed().as_millis() as u64,
                    },
                }
            });
            handles.push(handle);
        }
        
        // Wait for all tasks to complete
        let mut results = Vec::new();
        for handle in handles {
            match handle.await {
                Ok(result) => results.push(result),
                Err(e) => {
                    error!("Task handle error: {}", e);
                    results.push(ConcurrentTaskResult {
                        task_id: Uuid::new_v4(),
                        success: false,
                        result: None,
                        error: Some(format!("Task handle error: {}", e)),
                        execution_time_ms: 0,
                    });
                }
            }
        }
        
        results
    }
    
    /// Execute tasks with timeout
    pub async fn execute_with_timeout<F, T>(
        &self,
        task_id: Uuid,
        task_name: String,
        timeout_ms: u64,
        task: F,
    ) -> Result<T, String>
    where
        F: std::future::Future<Output = Result<T, String>> + Send + 'static,
        T: Send + 'static,
    {
        let timeout_duration = std::time::Duration::from_millis(timeout_ms);
        
        match tokio::time::timeout(timeout_duration, self.execute(task_id, task_name, task)).await {
            Ok(Ok(result)) => Ok(result),
            Ok(Err(e)) => Err(e),
            Err(_) => Err(format!("Task timed out after {}ms", timeout_ms)),
        }
    }
    
    /// Cancel a running task
    pub async fn cancel_task(&self, task_id: Uuid) -> bool {
        let mut tasks = self.active_tasks.write().await;
        if let Some(handle) = tasks.remove(&task_id) {
            handle.abort();
            info!("Cancelled task: {}", task_id);
            true
        } else {
            false
        }
    }
    
    /// Get number of active tasks
    pub async fn active_task_count(&self) -> usize {
        self.active_tasks.read().await.len()
    }
    
    /// Get maximum concurrent tasks
    pub fn max_concurrent(&self) -> usize {
        self.max_concurrent
    }
}

impl Clone for ConcurrentExecutor {
    fn clone(&self) -> Self {
        Self {
            semaphore: self.semaphore.clone(),
            max_concurrent: self.max_concurrent,
            active_tasks: self.active_tasks.clone(),
        }
    }
}

