use std::{collections::BTreeMap, fmt::Write};

use super::escape_label;

/// Low-cardinality labels recorded for a cache event.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct CacheMetricLabels {
    /// Cache component, for example `cache_aside`, `lru` or `two_level`.
    pub component: String,
    /// Cache operation category.
    pub operation: String,
    /// Result category.
    pub result: String,
}

impl CacheMetricLabels {
    /// Creates a cache event label set without carrying cache keys.
    pub fn new(
        component: impl Into<String>,
        operation: impl Into<String>,
        result: impl Into<String>,
    ) -> Self {
        Self {
            component: component.into(),
            operation: operation.into(),
            result: result.into(),
        }
    }
}

pub(crate) fn render(output: &mut String, metrics: &BTreeMap<CacheMetricLabels, u64>) {
    output.push_str(
        "# HELP rs_zero_cache_events_total Cache events by component, operation and result.\n",
    );
    output.push_str("# TYPE rs_zero_cache_events_total counter\n");
    for (labels, value) in metrics {
        writeln!(
            output,
            "rs_zero_cache_events_total{{component=\"{}\",operation=\"{}\",result=\"{}\"}} {}",
            escape_label(&labels.component),
            escape_label(&labels.operation),
            escape_label(&labels.result),
            value
        )
        .ok();
    }
}
