use std::collections::HashMap;

pub fn build_full_name(namespace: &str, subsystem: &str, name: &str) -> String {
    [namespace, subsystem, name]
        .iter()
        .filter(|s| !s.is_empty())
        .copied()
        .collect::<Vec<&str>>()
        .join("_")
}

pub fn kwargs_to_label_set(kwargs: HashMap<String, String>) -> Vec<(String, String)> {
    let mut labels: Vec<(String, String)> = kwargs.into_iter().collect();
    labels.sort_by(|a, b| a.0.cmp(&b.0));
    labels
}

pub fn args_to_label_set(
    label_names: &[String],
    args: Vec<String>,
) -> Result<Vec<(String, String)>, String> {
    if args.len() != label_names.len() {
        return Err(format!(
            "Expected {} label values, got {}",
            label_names.len(),
            args.len(),
        ));
    }
    let mut labels: Vec<(String, String)> = label_names.iter().cloned().zip(args).collect();
    labels.sort_by(|a, b| a.0.cmp(&b.0));
    Ok(labels)
}

pub fn validate_label_names(
    declared: &[String],
    provided: &HashMap<String, String>,
) -> Result<(), String> {
    if declared.len() != provided.len() {
        return Err(format!(
            "Expected {} labels {declared:?}, got {} {:?}",
            declared.len(),
            provided.len(),
            provided.keys().collect::<Vec<_>>(),
        ));
    }
    for name in declared {
        if !provided.contains_key(name) {
            return Err(format!(
                "Missing label '{name}'. Expected labels: {declared:?}",
            ));
        }
    }
    Ok(())
}
