/*
    Appellation: relationships <module>
    Contrib: @FL03
*/

/// Represents a relationship between two features
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[cfg_attr(
    feature = "serde",
    derive(serde_derive::Deserialize, serde_derive::Serialize)
)]
pub struct FeatureRelationship<T = f32> {
    /// Source feature ID
    pub(crate) from_id: usize,
    /// Target feature ID
    pub(crate) to_id: usize,
    /// Type of relationship
    pub(crate) relationship_type: RelationshipType,
    /// Strength/importance of relationship (0.0-1.0)
    pub(crate) strength: T,
    /// Occurrence count
    pub(crate) occurrences: usize,
}

/// Types of relationships between features
#[derive(
    Clone,
    Copy,
    Debug,
    Eq,
    Hash,
    Ord,
    PartialEq,
    PartialOrd,
    strum::AsRefStr,
    strum::Display,
    strum::EnumCount,
    strum::EnumIs,
    strum::EnumIter,
    strum::EnumString,
    strum::VariantArray,
    strum::VariantNames,
)]
#[cfg_attr(
    feature = "serde",
    derive(serde_derive::Deserialize, serde_derive::Serialize),
    serde(rename_all = "snake_case")
)]
#[strum(serialize_all = "snake_case")]
pub enum RelationshipType {
    /// One feature typically leads to another
    Causal,
    /// One feature is composed of other features
    Composition,
    Critical,
    Interval,
    /// Features are close in tonal space
    Proximity,
    /// Transformation from one feature to another
    Transformation,
}

impl<T> FeatureRelationship<T> {
    pub fn new(
        from_id: usize,
        to_id: usize,
        relationship_type: RelationshipType,
        strength: T,
    ) -> Self {
        Self {
            from_id,
            to_id,
            relationship_type,
            strength,
            occurrences: 1,
        }
    }

    gsw! {
        from_id: usize,
        to_id: usize,
        relationship_type: RelationshipType,
        occurrences: usize,
    }
    gsw! {
        strength: &T
    }
}
