/*
    Appellation: statistics <module>
    Contrib: @FL03
*/
use std::collections::HashMap;

/// Statistics about the memory system
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(
    feature = "serde",
    derive(serde_derive::Deserialize, serde_derive::Serialize)
)]
pub struct MemoryStatistics<T = f32> {
    /// Total number of features (including dead ones)
    pub total_features: usize,
    /// Number of active features
    pub active_features: usize,
    /// Count of features by dimension
    pub feature_counts_by_dimension: HashMap<usize, usize>,
    /// Average importance by dimension
    pub avg_importance_by_dimension: HashMap<usize, T>,
    /// Total number of relationships
    pub relationship_count: usize,
    /// Total number of patterns
    pub pattern_count: usize,
    /// Most common patterns (sequence, frequency)
    pub most_common_patterns: Vec<(Vec<usize>, usize)>,
    /// Current memory time
    pub memory_time: usize,
}

impl<T> MemoryStatistics<T> {
    /// Creates a new instance of `MemoryStatistics`
    pub fn new() -> Self {
        Self {
            total_features: 0,
            active_features: 0,
            feature_counts_by_dimension: HashMap::new(),
            avg_importance_by_dimension: HashMap::new(),
            relationship_count: 0,
            pattern_count: 0,
            most_common_patterns: Vec::new(),
            memory_time: 0,
        }
    }

    gsw! {
        active_features: usize,
        memory_time: usize,
        pattern_count: usize,
        relationship_count: usize,
        total_features: usize,
    }
    /// returns the average importance of a feature by dimension
    pub const fn avg_importance_by_dimension(&self) -> &HashMap<usize, T> {
        &self.avg_importance_by_dimension
    }
    /// returns a mutable reference to the average importance of a feature by dimension
    #[inline]
    pub fn avg_importance_by_dimension_mut(&mut self) -> &mut HashMap<usize, T> {
        &mut self.avg_importance_by_dimension
    }
    /// returns the number of features by dimension
    pub const fn feature_counts_by_dimension(&self) -> &HashMap<usize, usize> {
        &self.feature_counts_by_dimension
    }
    /// returns a mutable reference to the number of features by dimension
    #[inline]
    pub fn feature_counts_by_dimension_mut(&mut self) -> &mut HashMap<usize, usize> {
        &mut self.feature_counts_by_dimension
    }
    /// returns an immutable reference to the most common patterns
    pub const fn most_common_patterns(&self) -> &Vec<(Vec<usize>, usize)> {
        &self.most_common_patterns
    }
    /// returns a mutable reference to the most common patterns
    #[inline]
    pub fn most_common_patterns_mut(&mut self) -> &mut Vec<(Vec<usize>, usize)> {
        &mut self.most_common_patterns
    }

    pub fn generate_report(&self) -> String
    where
        T: core::fmt::Debug,
    {
        let mut lines = Vec::new();
        lines.push(format!(
            "Features (active / total): {} / {}",
            self.active_features, self.total_features
        ));
        lines.push(format!("Pattern count: {}", self.pattern_count));
        lines.push(format!("Relationship count: {}", self.relationship_count));

        lines.push(format!(
            "Average importance by dimension: {:?}",
            self.avg_importance_by_dimension
        ));
        lines.join("\n")
    }
}

impl<T> core::fmt::Display for MemoryStatistics<T>
where
    T: core::fmt::Debug,
{
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(
            f,
            "{{ total_features: {}, active_features: {}, feature_counts_by_dimension: {:?}, avg_importance_by_dimension: {:?}, relationship_count: {}, pattern_count: {}, most_common_patterns: {:?}, memory_time: {}}}",
            self.total_features,
            self.active_features,
            self.feature_counts_by_dimension,
            self.avg_importance_by_dimension,
            self.relationship_count,
            self.pattern_count,
            self.most_common_patterns,
            self.memory_time
        )
    }
}
