//! Simple monitoring module for batch workflow tests

use anyhow::Result;
use async_trait::async_trait;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use uuid::Uuid;

/// Workflow event for monitoring
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WorkflowEvent {
    pub workflow_id: Uuid,
    pub task_id: Option<Uuid>,
    pub event_type: String,
    pub metadata: serde_json::Value,
    pub timestamp: DateTime<Utc>,
}

/// Workflow metrics summary
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WorkflowMetrics {
    pub workflow_id: Uuid,
    pub total_tasks: u32,
    pub completed_tasks: u32,
    pub failed_tasks: u32,
    pub running_tasks: u32,
    pub total_duration_ms: u64,
    pub start_time: DateTime<Utc>,
    pub end_time: Option<DateTime<Utc>>,
}

/// Metrics trait for monitoring systems
#[async_trait]
pub trait Metrics: Send + Sync {
    async fn record_event(&self, event: WorkflowEvent);
    async fn get_workflow_metrics(&self, workflow_id: Uuid) -> Result<WorkflowMetrics>;
    async fn get_workflow_events(&self, workflow_id: Uuid) -> Result<Vec<WorkflowEvent>>;
}

/// In-memory metrics collector for testing
#[derive(Debug)]
pub struct MetricsCollector {
    events: Arc<Mutex<Vec<WorkflowEvent>>>,
    metrics: Arc<Mutex<HashMap<Uuid, WorkflowMetrics>>>,
}

impl MetricsCollector {
    pub fn new() -> Self {
        Self {
            events: Arc::new(Mutex::new(Vec::new())),
            metrics: Arc::new(Mutex::new(HashMap::new())),
        }
    }

    fn calculate_metrics(&self, workflow_id: Uuid) -> Result<WorkflowMetrics> {
        let events = self.events.lock().unwrap();
        let workflow_events: Vec<_> = events
            .iter()
            .filter(|e| e.workflow_id == workflow_id)
            .collect();

        if workflow_events.is_empty() {
            return Ok(WorkflowMetrics {
                workflow_id,
                total_tasks: 0,
                completed_tasks: 0,
                failed_tasks: 0,
                running_tasks: 0,
                total_duration_ms: 0,
                start_time: Utc::now(),
                end_time: None,
            });
        }

        let start_time = workflow_events
            .iter()
            .map(|e| e.timestamp)
            .min()
            .unwrap_or(Utc::now());

        let end_time = workflow_events
            .iter()
            .filter(|e| e.event_type == "workflow_completed" || e.event_type == "workflow_failed")
            .map(|e| e.timestamp)
            .max();

        let task_events: Vec<_> = workflow_events
            .iter()
            .filter(|e| e.task_id.is_some())
            .collect();

        let mut unique_tasks = std::collections::HashSet::new();
        let mut completed_tasks = 0;
        let mut failed_tasks = 0;
        let mut running_tasks = 0;

        for event in &task_events {
            if let Some(task_id) = event.task_id {
                unique_tasks.insert(task_id);

                match event.event_type.as_str() {
                    "task_completed" => completed_tasks += 1,
                    "task_failed" => failed_tasks += 1,
                    "task_started" => {
                        if !task_events.iter().any(|e|
                            e.task_id == Some(task_id) &&
                            (e.event_type == "task_completed" || e.event_type == "task_failed")
                        ) {
                            running_tasks += 1;
                        }
                    }
                    _ => {}
                }
            }
        }

        let total_duration_ms = if let Some(end) = end_time {
            (end - start_time).num_milliseconds().max(0) as u64
        } else {
            (Utc::now() - start_time).num_milliseconds().max(0) as u64
        };

        Ok(WorkflowMetrics {
            workflow_id,
            total_tasks: unique_tasks.len() as u32,
            completed_tasks,
            failed_tasks,
            running_tasks,
            total_duration_ms,
            start_time,
            end_time,
        })
    }
}

#[async_trait]
impl Metrics for MetricsCollector {
    async fn record_event(&self, event: WorkflowEvent) {
        let mut events = self.events.lock().unwrap();
        events.push(event.clone());

        // Update metrics cache
        if let Ok(metrics) = self.calculate_metrics(event.workflow_id) {
            let mut metrics_cache = self.metrics.lock().unwrap();
            metrics_cache.insert(event.workflow_id, metrics);
        }
    }

    async fn get_workflow_metrics(&self, workflow_id: Uuid) -> Result<WorkflowMetrics> {
        // Try cache first
        {
            let metrics = self.metrics.lock().unwrap();
            if let Some(cached) = metrics.get(&workflow_id) {
                return Ok(cached.clone());
            }
        }

        // Calculate fresh metrics
        self.calculate_metrics(workflow_id)
    }

    async fn get_workflow_events(&self, workflow_id: Uuid) -> Result<Vec<WorkflowEvent>> {
        let events = self.events.lock().unwrap();
        Ok(events
            .iter()
            .filter(|e| e.workflow_id == workflow_id)
            .cloned()
            .collect())
    }
}

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