/*
    Appellation: context <module>
    Contrib: @FL03
*/
use crate::types::MetricPosition;
use rstmt::HarmonicFunction;

/// The context for node operators; the context provides information about the current state of
/// the operator and its environment.
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(
    feature = "serde",
    derive(serde::Deserialize, serde::Serialize),
    serde(rename_all = "snake_case")
)]
pub struct ActorContext<T = f32> {
    /// Harmonic function (tonic, dominant, etc.)
    pub(crate) harmonic_function: Option<HarmonicFunction>,
    /// Metric position in a phrase
    pub(crate) metric_position: Option<MetricPosition>,
    /// Emotional/semantic tagging
    pub(crate) semantic_tags: Vec<String>,
    /// Stability rating (0.0-1.0)
    pub(crate) stability: T,
}

impl<T> ActorContext<T> {
    /// Create a new context with default values
    pub fn new() -> Self
    where
        T: num_traits::Zero,
    {
        Self {
            harmonic_function: None,
            metric_position: None,
            semantic_tags: Vec::new(),
            stability: T::zero(),
        }
    }
    /// returns a copy of the harmonic function
    pub const fn harmonic_function(&self) -> Option<HarmonicFunction> {
        self.harmonic_function
    }
    /// returns a copy of the metric position
    pub const fn metric_position(&self) -> Option<MetricPosition> {
        self.metric_position
    }
    /// returns an immutable reference to the semantic tags
    pub const fn semantic_tags(&self) -> &Vec<String> {
        &self.semantic_tags
    }
    /// returns a mutable reference to the semantic tags
    pub fn semantic_tags_mut(&mut self) -> &mut Vec<String> {
        &mut self.semantic_tags
    }
    /// returns an immutable reference to the stability rating
    pub const fn stability(&self) -> &T {
        &self.stability
    }
    /// Set the harmonic function
    pub fn set_harmonic_function(&mut self, function: Option<HarmonicFunction>) {
        self.harmonic_function = function;
    }
    /// Set the metric position
    pub fn set_metric_position(&mut self, position: Option<MetricPosition>) {
        self.metric_position = position;
    }
    /// Add a semantic tag
    pub fn push_semantic_tag(&mut self, tag: String) {
        self.semantic_tags.push(tag);
    }
    /// Set the stability rating
    pub fn set_stability(&mut self, stability: T) {
        self.stability = stability;
    }
    /// consumes the current instance to create another with the given harmonic function
    pub fn with_harmonic_function(self, function: HarmonicFunction) -> Self {
        Self {
            harmonic_function: Some(function),
            ..self
        }
    }
    /// consumes the current instance to create another with the given metric position
    pub fn with_metric_position(self, position: MetricPosition) -> Self {
        Self {
            metric_position: Some(position),
            ..self
        }
    }
    /// consumes the current instance to create another with the given semantic tags
    pub fn with_semantic_tags<I, U>(self, tags: I) -> Self
    where
        I: IntoIterator<Item = U>,
        U: ToString,
    {
        Self {
            semantic_tags: Vec::from_iter(tags.into_iter().map(|t| t.to_string())),
            ..self
        }
    }
    /// consumes the current instance to create another with the given stability rating
    pub fn with_stability(self, stability: T) -> Self {
        Self { stability, ..self }
    }
}

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