//! Predicate alias configuration.

use std::collections::HashMap;

use serde::Deserialize;

use crate::types::PredicateAliasSet;

/// Predicate alias configuration for semantic matching.
///
/// Allows defining sets of predicates that should be treated as equivalent
/// during conflict detection. For example, `enabled`, `required`, and `mandatory`
/// might all represent the same semantic concept.
///
/// # Example
///
/// ```toml
/// [predicate_aliases.sets]
/// enabled = ["required", "mandatory", "enforced", "active"]
/// version = ["min_version", "minimum_version", "tls_min_version"]
/// ```
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(default)]
pub struct PredicateAliasConfig {
    /// Named alias sets.
    ///
    /// The key is the canonical predicate name, and the value is a list of aliases.
    /// Example: `enabled = ["required", "mandatory"]`
    pub sets: HashMap<String, Vec<String>>,
}

impl PredicateAliasConfig {
    /// Convert config to a vector of PredicateAliasSet.
    pub fn to_alias_sets(&self) -> Vec<PredicateAliasSet> {
        self.sets
            .iter()
            .map(|(canonical, aliases)| PredicateAliasSet::new(canonical.clone(), aliases.clone()))
            .collect()
    }

    /// Normalize a predicate using configured aliases.
    ///
    /// Returns the canonical form if the predicate is aliased,
    /// otherwise returns the predicate unchanged.
    pub fn normalize(&self, predicate: &str) -> String {
        for (canonical, aliases) in &self.sets {
            if canonical == predicate || aliases.contains(&predicate.to_string()) {
                return canonical.clone();
            }
        }
        predicate.to_string()
    }
}
