// Variant generation matrix and rules
//
// This module defines which casing variants can be generated from each source
// casing convention based on the variant generation matrix in the specification.

use std::collections::{HashMap, HashSet};
use crate::case_transform::CasingConvention;

/// Encodes the rules for which variants can be generated from each source convention
#[derive(Debug)]
pub struct VariantGenerationMatrix {
    /// Source convention → Allowed target conventions
    matrix: HashMap<CasingConvention, HashSet<CasingConvention>>,
}

impl VariantGenerationMatrix {
    /// Create a new variant generation matrix with rules from the specification
    pub fn new() -> Self {
        let mut matrix = HashMap::new();
        
        // Multi-word conventions generate all 7 variants
        let all_conventions: HashSet<CasingConvention> = [
            CasingConvention::Lowercase,
            CasingConvention::Uppercase,
            CasingConvention::PascalCase,
            CasingConvention::CamelCase,
            CasingConvention::LowerSnakeCase,
            CasingConvention::ScreamingSnakeCase,
            CasingConvention::KebabCase,
        ].iter().copied().collect();
        
        matrix.insert(CasingConvention::PascalCase, all_conventions.clone());
        matrix.insert(CasingConvention::CamelCase, all_conventions.clone());
        matrix.insert(CasingConvention::LowerSnakeCase, all_conventions.clone());
        matrix.insert(CasingConvention::ScreamingSnakeCase, all_conventions.clone());
        matrix.insert(CasingConvention::KebabCase, all_conventions);
        
        // Single-word conventions generate only 3 variants
        let limited_variants: HashSet<CasingConvention> = [
            CasingConvention::Lowercase,
            CasingConvention::Uppercase,
            CasingConvention::PascalCase,
        ].iter().copied().collect();
        
        matrix.insert(CasingConvention::Uppercase, limited_variants.clone());
        matrix.insert(CasingConvention::Lowercase, limited_variants);
        
        // Fallback generates no variants (used as-is)
        let mut fallback_variants = HashSet::new();
        fallback_variants.insert(CasingConvention::Lowercase);
        matrix.insert(CasingConvention::Fallback, fallback_variants);
        
        Self { matrix }
    }
    
    /// Check if a variant can be generated from source to target convention
    pub fn can_generate(&self, source: CasingConvention, target: CasingConvention) -> bool {
        self.matrix
            .get(&source)
            .map(|allowed| allowed.contains(&target))
            .unwrap_or(false)
    }
    
    /// Get all allowed target conventions for a source convention
    pub fn allowed_variants(&self, source: CasingConvention) -> Option<&HashSet<CasingConvention>> {
        self.matrix.get(&source)
    }
}

impl Default for VariantGenerationMatrix {
    fn default() -> Self {
        Self::new()
    }
}
