use prometheus::{
    register_counter, register_int_gauge, Counter, Histogram, HistogramOpts, IntGauge, Registry,
};

pub struct WorkflowMetrics {
    pub workflows_started: Counter,
    pub workflows_completed: Counter,
    pub workflows_failed: Counter,
    pub stages_completed: Counter,
    pub active_workflows: IntGauge,
    pub stage_duration_seconds: Histogram,
    pub workflow_duration_seconds: Histogram,
    // Scheduling subsystem
    pub schedules_fired: Counter,
    pub schedules_skipped: Counter,
    pub schedules_failed: Counter,
    pub active_schedules: IntGauge,
}

impl WorkflowMetrics {
    pub fn new() -> Result<Self, prometheus::Error> {
        Ok(Self {
            workflows_started: register_counter!(
                "vapora_workflows_started_total",
                "Total workflows started"
            )?,
            workflows_completed: register_counter!(
                "vapora_workflows_completed_total",
                "Total workflows completed successfully"
            )?,
            workflows_failed: register_counter!(
                "vapora_workflows_failed_total",
                "Total workflows failed"
            )?,
            stages_completed: register_counter!(
                "vapora_stages_completed_total",
                "Total stages completed"
            )?,
            active_workflows: register_int_gauge!(
                "vapora_active_workflows",
                "Currently active workflows"
            )?,
            stage_duration_seconds: Histogram::with_opts(
                HistogramOpts::new("vapora_stage_duration_seconds", "Stage execution duration")
                    .buckets(vec![1.0, 5.0, 15.0, 30.0, 60.0, 120.0, 300.0]),
            )?,
            workflow_duration_seconds: Histogram::with_opts(
                HistogramOpts::new(
                    "vapora_workflow_duration_seconds",
                    "Workflow total duration",
                )
                .buckets(vec![60.0, 300.0, 600.0, 1800.0, 3600.0]),
            )?,
            schedules_fired: register_counter!(
                "vapora_schedules_fired_total",
                "Total schedule fires that launched a workflow"
            )?,
            schedules_skipped: register_counter!(
                "vapora_schedules_skipped_total",
                "Total schedule fires skipped due to allow_concurrent=false"
            )?,
            schedules_failed: register_counter!(
                "vapora_schedules_failed_total",
                "Total schedule fires that failed to start a workflow"
            )?,
            active_schedules: register_int_gauge!(
                "vapora_active_schedules",
                "Number of enabled scheduled workflows"
            )?,
        })
    }

    pub fn register(&self, registry: &Registry) -> Result<(), prometheus::Error> {
        registry.register(Box::new(self.workflows_started.clone()))?;
        registry.register(Box::new(self.workflows_completed.clone()))?;
        registry.register(Box::new(self.workflows_failed.clone()))?;
        registry.register(Box::new(self.stages_completed.clone()))?;
        registry.register(Box::new(self.active_workflows.clone()))?;
        registry.register(Box::new(self.stage_duration_seconds.clone()))?;
        registry.register(Box::new(self.workflow_duration_seconds.clone()))?;
        registry.register(Box::new(self.schedules_fired.clone()))?;
        registry.register(Box::new(self.schedules_skipped.clone()))?;
        registry.register(Box::new(self.schedules_failed.clone()))?;
        registry.register(Box::new(self.active_schedules.clone()))?;
        Ok(())
    }
}

impl Default for WorkflowMetrics {
    fn default() -> Self {
        Self::new().expect("Failed to create workflow metrics")
    }
}

#[cfg(test)]
mod tests {
    use prometheus::{Counter, Histogram, HistogramOpts, IntGauge};

    use super::*;

    #[test]
    fn test_metrics_operations() {
        let counter = Counter::new("test_counter", "test").unwrap();
        counter.inc();
        assert_eq!(counter.get(), 1.0);

        let gauge = IntGauge::new("test_gauge", "test").unwrap();
        gauge.set(5);
        assert_eq!(gauge.get(), 5);

        let histogram = Histogram::with_opts(HistogramOpts::new("test_hist", "test")).unwrap();
        histogram.observe(10.5);
        histogram.observe(25.3);
    }

    #[test]
    fn test_metrics_registry() {
        let registry = Registry::new();
        let counter = Counter::new("workflow_test", "test").unwrap();
        assert!(registry.register(Box::new(counter)).is_ok());
    }
}
