use std::collections::HashMap;
use std::net::SocketAddr;

use serde::{Deserialize, Serialize};

/// Type of a custom metric declared in config.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum CollectorType {
    Counter,
    Gauge,
    Histogram,
}

/// A user-defined metric declared in `[[metrics.collectors]]`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CollectorDef {
    pub name: String,
    #[serde(rename = "type")]
    pub collector_type: CollectorType,
    #[serde(default)]
    pub help: String,
    #[serde(default)]
    pub labels: Vec<String>,
    /// Histogram bucket boundaries. Only used when type = "histogram".
    #[serde(default)]
    pub buckets: Vec<f64>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct MetricsConfig {
    /// Listening address for metrics/health/ready endpoints. Default: 0.0.0.0:9090
    pub listen: SocketAddr,
    /// Namespace prefix for all metrics (e.g. "folk" → folk_*). Default: "folk"
    pub prefix: String,
    /// Path for Prometheus scrape endpoint. Default: "/metrics"
    pub metrics_path: String,
    /// Path for liveness probe. Default: "/health"
    pub health_path: String,
    /// Path for readiness probe. Default: "/ready"
    pub ready_path: String,
    /// Per-plugin metric filtering. Missing = enabled. Set false to disable.
    #[serde(default)]
    pub plugins: HashMap<String, bool>,
    /// Custom metrics declared by the user.
    #[serde(default)]
    pub collectors: Vec<CollectorDef>,
}

impl Default for MetricsConfig {
    fn default() -> Self {
        Self {
            listen: "0.0.0.0:9090".parse().unwrap(),
            prefix: "folk".into(),
            metrics_path: "/metrics".into(),
            health_path: "/health".into(),
            ready_path: "/ready".into(),
            plugins: HashMap::new(),
            collectors: Vec::new(),
        }
    }
}

impl MetricsConfig {
    /// Returns the set of disabled plugin metric prefixes based on `plugins` config.
    /// Maps plugin name → metric name prefixes to filter out.
    pub fn disabled_prefixes(&self) -> Vec<&'static str> {
        let mut disabled = Vec::new();
        for (plugin, enabled) in &self.plugins {
            if *enabled {
                continue;
            }
            let prefixes: &[&str] = match plugin.as_str() {
                "core" => &[
                    "folk_workers_",
                    "folk_worker_",
                    "folk_request_",
                    "folk_boot_",
                ],
                "http" => &["folk_http_"],
                "jobs" => &["folk_jobs_"],
                "grpc" => &["folk_grpc_"],
                "process" => &["folk_process_"],
                _ => &[],
            };
            disabled.extend_from_slice(prefixes);
        }
        disabled
    }
}
