/*
    Appellation: impl_vnode <module>
    Contrib: @FL03
*/
use super::VNode;

use crate::ctx::ActorContext;
use crate::drivers::{Driver, RawDriver, TriadDriver};
use crate::mem::prelude::{MemoryStatistics, RelationshipType};
use crate::operators::Operator;
use crate::surface::{Predict, SurfaceModel, SurfaceNetwork, Train};
use crate::traits::{Actor, ActorExt};
use crate::types::StabilityPattern;

use ndarray::{Array1, Array2, ScalarOperand};
use num_traits::{Float, FromPrimitive, NumAssign, ToPrimitive};
use rshyper::EdgeId;
use rstmt::nrt::{LPR, Triad, Triads};
use rstmt::{Aspn, PitchMod};
use std::collections::HashMap;
use std::time::Duration;

impl<D, T> VNode<D, T>
where
    D: RawDriver<Triad>,
    T: Float
        + FromPrimitive
        + ToPrimitive
        + NumAssign
        + ScalarOperand
        + core::iter::Sum
        + core::str::FromStr,
{
    /// Apply learned stability patterns from another triad class to the current one
    pub fn adapt_stability_patterns(&mut self, source_class: Triads) -> crate::Result<()> {
        // Create patterns for the source class
        let _source = self.create_stability_patterns_for_class(source_class);

        // Create patterns for the current class
        let _target = self.create_stability_patterns_for_class(self.class());

        // Learn the appropriate patterns with adaptation

        todo!("update the method to reflect modifications to the network");
        // // First learn the original patterns to understand the source
        // let mut all_inputs = Vec::new();
        // let mut all_targets = Vec::new();

        // // Use source patterns to understand the origin
        // for (input, target) in &source_patterns {
        //     all_inputs.push(*input);
        //     all_targets.push(*target);
        // }

        // // Then add target patterns for adaptation
        // for (input, target) in &target_patterns {
        //     all_inputs.push(*input);
        //     all_targets.push(*target);
        // }

        // // Learn with prioritizing target patterns (more iterations)
        // self.learn_pattern(&all_inputs, &all_targets, 500)?;

        // Ok(())
    }
    /// Adapt the surface network weights based on patterns from another node
    pub fn adapt_surface_to_external_patterns<I>(&mut self, patterns: I) -> crate::Result<()>
    where
        I: IntoIterator<Item = Vec<usize>>,
    {
        // Ensure we have a surface network
        if let Some(surface) = &mut self.surface {
            // We need to reconstruct meaningful weight adjustments from discrete patterns
            let mut adaptation_count = 0;
            let scale = T::from_usize(1000).unwrap(); // Same scale used in extract_knowledge_patterns

            for pattern in patterns {
                // Skip patterns that don't have our marker or are too short
                if pattern.len() < 4 || pattern[0] != 999 {
                    continue;
                }

                // Check pattern type (1 = primary, 2 = secondary)
                let is_primary = pattern[1] == 1;

                if is_primary {
                    // Process primary weights starting at index 2
                    for i in (2..pattern.len()).step_by(2) {
                        if i + 1 >= pattern.len() {
                            continue;
                        }

                        let position = pattern[i];
                        let quantized_value = pattern[i + 1];

                        // Calculate row and column from position
                        let (in_rows, in_cols) = surface.model().features().dim_input();
                        let row = position / in_cols;
                        let col = position % in_cols;

                        // Check bounds
                        if row < in_rows && col < in_cols {
                            // Dequantize value
                            let weight_value = T::from_usize(quantized_value).unwrap() / scale;

                            // Adaptive integration - more conservative than full replacement
                            let current = surface.input().weights()[[row, col]];
                            let new_value = current * T::from_f32(0.85).unwrap()
                                + weight_value * T::from_f32(0.15).unwrap();
                            surface.input_mut().weights_mut()[[row, col]] = new_value;

                            adaptation_count += 1;
                        }
                    }
                } else {
                    // Process secondary weights
                    for i in (2..pattern.len()).step_by(2) {
                        if i + 1 >= pattern.len() {
                            continue;
                        }

                        let col = pattern[i];
                        let quantized_value = pattern[i + 1];

                        // Check bounds
                        if col < surface.output().ncols() {
                            // Dequantize value
                            let weight_value = T::from_usize(quantized_value).unwrap() / scale;

                            // Adaptive integration - more conservative than full replacement
                            let current = surface.output().weights()[[0, col]];
                            let new_value = current * T::from_f32(0.85).unwrap()
                                + weight_value * T::from_f32(0.15).unwrap();
                            surface.output_mut().weights_mut()[[0, col]] = new_value;

                            adaptation_count += 1;
                        }
                    }
                }
            }

            // If we made adaptations, record this in memory
            if adaptation_count > 0 {
                self.store
                    .record_event("adapted_surface", Some(vec![adaptation_count]));
            }
        }

        Ok(())
    }
    /// Adjust surface parameters towards target parameters
    pub fn adjust_surface_parameters(&mut self, target: &(T, T, T), rate: T) -> crate::Result<()> {
        if let Some(surface) = &mut self.surface {
            // Interpolate between current and target parameters
            let lr = *surface.model().learning_rate();
            let decay = *surface.model().decay();
            let momentum = *surface.model().momentum();
            let new_gamma = lr + rate * (target.2 - lr);
            let new_decay = decay + rate * (target.1 - decay);
            let new_momentum = momentum + rate * (target.0 - momentum);

            // Apply adjusted parameters
            let config =
                crate::surface::SurfaceModelConfig::new(new_gamma, new_momentum, new_decay);
            surface.model_mut().set_config(config);
        }

        Ok(())
    }
    /// Apply federated gradients to local model
    pub fn apply_federated_gradients(
        &mut self,
        averaged_gradients: &HashMap<String, Vec<Vec<T>>>,
    ) -> crate::Result<()> {
        if let Some(surface) = &mut self.surface {
            // Apply averaged primary gradients if available
            if let Some(primary_grads) = averaged_gradients.get("primary") {
                if !primary_grads.is_empty() {
                    // Calculate average gradient
                    let mut avg_grad = vec![T::zero(); primary_grads[0].len()];

                    for grad in primary_grads {
                        for (i, &value) in grad.iter().enumerate() {
                            if i < avg_grad.len() {
                                avg_grad[i] += value / T::from_usize(primary_grads.len()).unwrap();
                            }
                        }
                    }

                    // Apply to primary weights
                    let mut idx = 0;
                    for i in 0..surface.input().nrows() {
                        for j in 0..surface.input().ncols() {
                            if idx < avg_grad.len() {
                                surface.input_mut().weights_mut()[[i, j]] =
                                    T::from_f32(0.9).unwrap() * surface.input().weights()[[i, j]]
                                        + T::from_usize(10).unwrap().recip() * avg_grad[idx];
                                idx += 1;
                            }
                        }
                    }
                }
            }

            // Apply averaged secondary gradients if available
            if let Some(secondary_grads) = averaged_gradients.get("secondary") {
                if !secondary_grads.is_empty() {
                    // Calculate average gradient
                    let mut avg_grad = vec![T::zero(); secondary_grads[0].len()];

                    for grad in secondary_grads {
                        for (i, &value) in grad.iter().enumerate() {
                            if i < avg_grad.len() {
                                avg_grad[i] +=
                                    value / T::from_usize(secondary_grads.len()).unwrap();
                            }
                        }
                    }

                    // Apply to secondary weights
                    let mut idx = 0;
                    for i in 0..surface.output().nrows() {
                        for j in 0..surface.output().ncols() {
                            if idx < avg_grad.len() {
                                surface.output_mut().weights_mut()[[i, j]] =
                                    T::from_f32(0.9).unwrap() * surface.output().weights()[[i, j]]
                                        + T::from_usize(10).unwrap().recip() * avg_grad[idx];
                                idx += 1;
                            }
                        }
                    }
                }
            }
        }

        Ok(())
    }
    /// Calculate adaptive target for maximum feature count
    pub fn calculate_adaptive_feature_target(&self) -> usize
    where
        T: core::str::FromStr,
    {
        // Base target depends on the node's role
        let base_target = match self.operator() {
            Operator::Observer(_) => 2000, // Observers can store more features
            Operator::Agent(_) => 1500,    // Agents need to be more efficient
        };
        let base_target = T::from_usize(base_target).unwrap();

        // Adjust based on critical point count (more critical points -> more memory needed)
        let critical_point_factor =
            T::from_f32(1.0 + (self.critical_points().len() as f32 * 0.1)).unwrap();

        // Adjust based on learning quality
        let learning_accuracy = self.get_learning_accuracy();
        let learning_factor = if learning_accuracy > T::from_f32(0.8).unwrap() {
            // Good learning - allow more memory to capture nuances
            T::from_f32(1.2).unwrap()
        } else if learning_accuracy > T::from_f32(0.5).unwrap() {
            // Average learning - normal memory allocation
            T::one()
        } else {
            // Poor learning - restrict memory to force better generalization
            T::from_f32(0.8).unwrap()
        };

        // Final target calculation
        let adaptive_target = (base_target * critical_point_factor * learning_factor)
            .to_usize()
            .unwrap();

        // Ensure reasonable bounds
        adaptive_target.clamp(500, 5000)
    }
    /// Consolidate similar patterns to reduce memory usage
    pub fn consolidate_similar_patterns(
        &mut self,
        similarity_threshold: T,
    ) -> crate::Result<usize> {
        // Create a memory buffer to avoid modifying while iterating
        let feature_ids: Vec<_> = self
            .store
            .features()
            .iter()
            .filter(|f| f.dimension() == 2 && f.death().is_none())
            .map(|f| f.id())
            .collect();

        // Track how many features were consolidated
        let mut consolidated_count = 0;

        // Find similar patterns and merge them
        for i in 0..feature_ids.len() {
            // Skip already processed features
            if i >= feature_ids.len() {
                continue;
            }

            let id1 = feature_ids[i];

            // Get the first feature, skip if already deleted
            let f1 = match self.store().find_feature_by_id(id1).cloned() {
                Some(f) if f.death().is_none() => f,
                _ => continue,
            };

            // Compare with all subsequent features
            for j in i + 1..feature_ids.len() {
                let id2 = feature_ids[j];

                // Get the second feature, skip if already deleted
                let f2 = match self.store().find_feature_by_id(id2).cloned() {
                    Some(f) if f.death().is_none() => f,
                    _ => continue,
                };

                // Only compare features of the same dimension
                if f1.dimension() != f2.dimension() {
                    continue;
                }

                // Calculate similarity between the features
                let similarity = self
                    .store()
                    .content_similarity(f1.content().as_slice(), f2.content().as_slice());

                // If similarity is above threshold, merge the features
                if similarity >= similarity_threshold {
                    // Keep the more important feature
                    let (keep_id, remove_id) = if f1.importance() >= f2.importance() {
                        (id1, id2)
                    } else {
                        (id2, id1)
                    };

                    // Merge the features
                    self.store.merge_features(keep_id, remove_id);
                    consolidated_count += 1;
                }
            }
        }

        Ok(consolidated_count)
    }
    /// Get contextual information about the current state
    pub fn contextualize(&mut self) -> crate::Result<ActorContext<T>> {
        // Check if we have a recent cached context
        if let Some((context, timestamp)) = self.last_context() {
            // Use cached context if it's recent enough (within 100ms)
            if timestamp.elapsed() < Duration::from_millis(100) {
                return Ok(context.clone());
            }
        }

        // Generate new context
        let ctx = self.generate_context()?;
        self.set_last_context(ctx);
        self.last_context().map_or_else(
            || Err(crate::ActorError::GenerativeError("".to_string())),
            |(c, _)| Ok(c.clone()),
        )
    }
    /// Create stability patterns specific to the current headspace
    pub fn create_stability_patterns_for_class(&self, class: Triads) -> Vec<StabilityPattern<T>> {
        match class {
            Triads::Major => {
                vec![
                    (
                        [
                            T::from_f32(0.8).unwrap(),
                            T::from_f32(0.1).unwrap(),
                            T::from_f32(0.1).unwrap(),
                        ],
                        Array1::ones(3),
                    ), // Root emphasis - high stability
                    (
                        [
                            T::from_f32(0.1).unwrap(),
                            T::from_f32(0.8).unwrap(),
                            T::from_f32(0.1).unwrap(),
                        ],
                        Array1::from_elem(3, T::from_f32(0.5).unwrap()),
                    ), // Third emphasis - medium stability
                    (
                        [
                            T::from_f32(0.1).unwrap(),
                            T::from_f32(0.1).unwrap(),
                            T::from_f32(0.8).unwrap(),
                        ],
                        Array1::zeros(3),
                    ), // Fifth emphasis - low stability
                    (
                        [T::from_f32(3.0.recip()).unwrap(); 3],
                        Array1::from_elem(3, T::from_f32(0.5).unwrap()),
                    ), // Balanced - medium stability
                ]
            }
            Triads::Minor => {
                vec![
                    (
                        [
                            T::from_f32(0.8).unwrap(),
                            T::from_f32(0.1).unwrap(),
                            T::from_f32(0.1).unwrap(),
                        ],
                        Array1::from_elem(3, T::from_f32(0.5).unwrap()),
                    ), // Root emphasis - medium stability
                    (
                        [
                            T::from_f32(0.1).unwrap(),
                            T::from_f32(0.8).unwrap(),
                            T::from_f32(0.1).unwrap(),
                        ],
                        Array1::zeros(3),
                    ), // Third emphasis - low stability
                    (
                        [
                            T::from_f32(0.1).unwrap(),
                            T::from_f32(0.1).unwrap(),
                            T::from_f32(0.8).unwrap(),
                        ],
                        Array1::ones(3),
                    ), // Fifth emphasis - high stability
                    (
                        [T::from_f32(3.0.recip()).unwrap(); 3],
                        Array1::from_elem(3, T::from_f32(0.5).unwrap()),
                    ), // Balanced - medium stability
                ]
            }
            Triads::Diminished => {
                vec![
                    (
                        [
                            T::from_f32(0.8).unwrap(),
                            T::from_f32(0.1).unwrap(),
                            T::from_f32(0.1).unwrap(),
                        ],
                        Array1::from_elem(3, T::from_f32(0.4).unwrap()),
                    ), // Root emphasis - moderate stability
                    (
                        [
                            T::from_f32(0.1).unwrap(),
                            T::from_f32(0.8).unwrap(),
                            T::from_f32(0.1).unwrap(),
                        ],
                        Array1::from_elem(3, T::from_f32(0.3).unwrap()),
                    ), // Third emphasis - lower stability
                    (
                        [
                            T::from_f32(0.1).unwrap(),
                            T::from_f32(0.1).unwrap(),
                            T::from_f32(0.8).unwrap(),
                        ],
                        Array1::from_elem(3, T::from_f32(0.2).unwrap()),
                    ), // Fifth emphasis - least stability
                    (
                        [T::from_f32(3.0.recip()).unwrap(); 3],
                        Array1::from_elem(3, T::from_f32(0.3).unwrap()),
                    ), // Balanced - moderate stability
                ]
            }
            Triads::Augmented => {
                vec![
                    (
                        [
                            T::from_f32(0.8).unwrap(),
                            T::from_f32(0.1).unwrap(),
                            T::from_f32(0.1).unwrap(),
                        ],
                        Array1::from_elem(3, T::from_f32(0.5).unwrap()),
                    ), // Root emphasis - medium stability
                    (
                        [
                            T::from_f32(0.1).unwrap(),
                            T::from_f32(0.8).unwrap(),
                            T::from_f32(0.1).unwrap(),
                        ],
                        Array1::from_elem(3, T::from_f32(0.5).unwrap()),
                    ), // Third emphasis - medium stability
                    (
                        [
                            T::from_f32(0.1).unwrap(),
                            T::from_f32(0.1).unwrap(),
                            T::from_f32(0.8).unwrap(),
                        ],
                        Array1::from_elem(3, T::from_f32(0.5).unwrap()),
                    ), // Fifth emphasis - medium stability
                    (
                        [T::from_f32(3.0.recip()).unwrap(); 3],
                        Array1::from_elem(3, T::from_f32(0.5).unwrap()),
                    ), // Balanced - medium stability
                ]
            }
        }
    }
    /// Calculate distance from headspace root to critical point
    pub fn distance_to_critical_point(&self, name: &str) -> Option<usize> {
        if let Some(&pitch_class) = self.critical_points.get(name) {
            let root = self.headspace().root();
            let distance = ((pitch_class as isize - root as isize).pmod()) as usize;
            Some(distance)
        } else {
            None
        }
    }
    /// Calculate distance to a point
    pub fn distance_to_point(&self, point: usize) -> usize {
        let current = self.driver.headspace();
        let mut min_distance = 12;

        for note in current.notes() {
            let raw_distance = ((note as isize) - (point as isize)).abs().pmod();
            let distance = core::cmp::min(raw_distance, 12 - raw_distance) as usize;
            min_distance = core::cmp::min(min_distance, distance);
        }

        min_distance
    }
    /// Ensure the surface network is initialized
    #[cfg(not(feature = "rand"))]
    pub fn ensure_surface_network(&mut self) -> crate::Result<&mut SurfaceNetwork<T>> {
        if self.surface.is_none() {
            self.init_surface()?;
        }
        self.surface
            .as_mut()
            .ok_or(crate::ActorError::NotInitialized(
                "Unable to initialize the surface network".to_string(),
            ))
    }
    #[cfg(feature = "rand")]
    pub fn ensure_surface_network(&mut self) -> crate::Result<&mut SurfaceNetwork<T>>
    where
        rand_distr::StandardNormal: rand_distr::Distribution<T>,
    {
        if self.surface.is_none() {
            self.init_surface()?;
        }
        self.surface
            .as_mut()
            .ok_or(crate::ActorError::NotInitialized(
                "Unable to initialize the surface network".to_string(),
            ))
    }
    /// Extract knowledge patterns in a discrete form
    pub fn extract_knowledge_patterns(&self) -> crate::Result<Vec<Vec<usize>>> {
        let mut patterns = Vec::new();

        // Extract from memory features
        // Get stabilized patterns (dimension 2 features that have persisted)
        for feature in self.store().features() {
            if feature.dimension() == 2
                && feature.death().is_none()
                && feature.importance() > &T::from_f32(0.6).unwrap()
            {
                patterns.push(feature.content().to_vec());
            }
        }

        // If we have a surface network, extract learned patterns
        if let Some(surface) = &self.surface {
            // Convert floating point weights to discrete representations
            let inputs = surface.input();
            let outputs = surface.output();

            // Quantize weights (convert T to usize with scaling)
            let scale = T::from_usize(1000).unwrap();

            // Process primary weights
            for i in 0..inputs.nrows() {
                let mut pattern = Vec::with_capacity(inputs.ncols() * 2 + 2);
                pattern.push(999); // Marker for surface weights
                pattern.push(1); // Primary weight indicator

                for j in 0..inputs.ncols() {
                    let value = inputs.weights()[[i, j]] * scale;
                    pattern.push(i * inputs.ncols() + j); // Position
                    // Quantized weight
                    if let Some(value) = value.to_usize() {
                        pattern.push(value); // Convert to usize
                    } else {
                        pattern.push(0); // Fallback for non-integer values
                    }
                }
                patterns.push(pattern);
            }

            // Process secondary weights
            let mut pattern = Vec::with_capacity(outputs.ncols() * 2 + 2);
            pattern.push(999); // Marker for surface weights
            pattern.push(2); // Secondary weight indicator

            for j in 0..outputs.ncols() {
                let value = (outputs.weights()[[0, j]] * scale).to_usize().unwrap();
                pattern.push(j); // Position
                pattern.push(value); // Quantized weight
            }
            patterns.push(pattern);
        }

        Ok(patterns)
    }
    /// Extract learning gradients for federated learning
    pub fn extract_learning_gradients(&self) -> crate::Result<HashMap<String, Vec<T>>> {
        let mut gradients = HashMap::new();

        if let Some(surface) = &self.surface {
            // Extract gradients from surface network
            // Pattern ID -> Gradient vector
            let input_weights = surface.input().weights();
            let output_weights = surface.output().weights();

            // Flatten weights into gradient vectors
            let mut input_delta = Vec::with_capacity(input_weights.len());
            for i in 0..input_weights.nrows() {
                for j in 0..input_weights.ncols() {
                    input_delta.push(input_weights[[i, j]]);
                }
            }

            let mut output_delta = Vec::with_capacity(output_weights.len());
            for i in 0..output_weights.nrows() {
                for j in 0..output_weights.ncols() {
                    output_delta.push(output_weights[[i, j]]);
                }
            }

            // Store gradients with pattern IDs
            gradients.insert("primary".to_string(), input_delta);
            gradients.insert("secondary".to_string(), output_delta);
        }

        Ok(gradients)
    }
    /// Find features related to the current triad
    pub fn find_related_triads(&self) -> Vec<Triad> {
        // Get current triad feature
        let current_notes = self.get_notes().to_vec();

        // Find features with the same content
        let current_features = self.store.find_by_content_prefix(&current_notes);

        if current_features.is_empty() {
            return Vec::new();
        }

        // Get related features through relationships
        let mut related_features = Vec::new();
        for feature in current_features {
            let related = self
                .store
                .find_related_features(feature.id(), Some(RelationshipType::Transformation));
            related_features.extend(related);
        }

        // Convert features to triads
        related_features
            .into_iter()
            .filter(|f| f.dimension() == 2 && f.content().len() == 3)
            .map(|f| {
                // Determine class by checking if its major or minor
                let notes = [f[0], f[1], f[2]];
                let root = notes[0];
                let third_interval = (notes[1] + 12 - root).pmod();
                let class = if third_interval == 4 {
                    Triads::Major
                } else {
                    Triads::Minor
                };

                Triad::new(notes, class)
            })
            .collect()
    }
    /// Find paths to a triad containing the target pitch
    pub fn find_paths_to_point(&self, target: usize) -> Vec<Vec<LPR>> {
        // use the pathfinder to find paths to the target pitch
        self.driver()
            .headspace()
            .path_finder()
            .find_paths_to_target(target)
            .into_iter()
            .map(|tgt| tgt.path().clone())
            .collect::<Vec<_>>()
    }
    /// Get a list of triads that have been frequently visited
    pub fn get_frequently_visited_triads(&self, min_occurrences: usize) -> Vec<Triad> {
        // Get all triad features (dimension 2)
        let triad_features = self.store.find_by_dimension(2);

        // Count the occurrences of each triad
        let mut triad_counts = HashMap::new();
        for feature in triad_features {
            if feature.content_len() == 3 {
                let notes = [feature[0], feature[1], feature[2]];
                *triad_counts.entry(notes).or_insert(0) += 1;
            }
        }

        // Filter by minimum occurrences and convert to Triads
        triad_counts
            .into_iter()
            .filter(|(_, count)| *count >= min_occurrences)
            .map(|(notes, _)| {
                // Determine class by checking if its major or minor
                let root = notes[0];
                let third_interval = (notes[1] + 12 - root).pmod();
                let class = if third_interval == 4 {
                    Triads::Major
                } else {
                    Triads::Minor
                };

                Triad::new(notes, class)
            })
            .collect()
    }
    /// Get convergence rate for learning
    pub fn get_convergence_rate(&self) -> T {
        // Check if we have convergence metrics
        if let Some(convergence) = self.store.get_property_float("convergence_rate") {
            return convergence;
        }

        // Default value if no metrics available
        T::from_f32(0.5).unwrap()
    }
    /// Get feature quality metric
    pub fn get_feature_quality(&self) -> T {
        // Use feature count as a proxy for quality
        let feature_count = T::from_usize(self.total_features()).unwrap();
        (feature_count / T::from_usize(100).unwrap()).min(T::one())
    }
    /// Get the current learning accuracy
    pub fn get_learning_accuracy(&self) -> T
    where
        T: core::str::FromStr,
    {
        self.store()
            .get_property("learning_accuracy")
            .and_then(|i| i.parse().ok())
            .unwrap_or(T::from_f32(0.5).unwrap())
    }
    /// Get statistics about the memory state
    pub fn get_memory_statistics(&self) -> MemoryStatistics<T> {
        self.store().get_statistics()
    }
    /// Get learned stability patterns from this node's surface network
    pub fn get_stability_patterns(&self) -> Option<Vec<StabilityPattern<T>>>
    where
        SurfaceModel<T>: Predict<Array1<T>, Output = Array1<T>>,
    {
        if !self.has_surface_network() {
            return None;
        }

        // Generate representative patterns based on current headspace
        let mut patterns = Vec::new();
        let p1 = T::from_usize(10).unwrap().recip();
        let p5 = T::from_f32(0.5).unwrap();
        let p8 = T::from_f32(0.8).unwrap();
        let p118 = [p1, p1, p8];
        let p181 = [p1, p8, p1];
        let p811 = [p8, p1, p1];

        // Add standard patterns based on chord type
        match self.class() {
            Triads::Major => {
                // In major triads:
                // - Root emphasis creates stability
                // - Fifth emphasis creates tension
                // - Third emphasis creates moderate stability
                patterns.push((
                    p811,
                    self.process_surface(&Array1::from_iter(p811))
                        .unwrap_or(Array1::ones(3)),
                ));
                patterns.push((
                    p181,
                    self.process_surface(&Array1::from_iter(p181))
                        .unwrap_or(Array1::from_elem(3, T::from_f32(0.5).unwrap())),
                ));
                patterns.push((
                    p118,
                    self.process_surface(&Array1::from_iter(p118))
                        .unwrap_or(Array1::zeros(3)),
                ));
            }
            Triads::Minor => {
                // In minor triads:
                // - Fifth emphasis creates stability
                // - Third emphasis creates tension
                // - Root emphasis creates moderate stability
                patterns.push((
                    p118,
                    self.process_surface(&Array1::from_iter(p118))
                        .unwrap_or(Array1::ones(3)),
                ));
                patterns.push((
                    p811,
                    self.process_surface(&Array1::from_iter(p811))
                        .unwrap_or(Array1::from_elem(3, T::from_f32(0.5).unwrap())),
                ));
                patterns.push((
                    p181,
                    self.process_surface(&Array1::from_iter(p181))
                        .unwrap_or(Array1::zeros(3)),
                ));
            }
            Triads::Diminished => {
                // In diminished triads, more subtle differences
                patterns.push((
                    p811,
                    self.process_surface(&Array1::from_iter(p811))
                        .unwrap_or(Array1::from_elem(3, T::from_f32(0.4).unwrap())),
                ));
                patterns.push((
                    p181,
                    self.process_surface(&Array1::from_iter(p181))
                        .unwrap_or(Array1::from_elem(3, T::from_f32(0.3).unwrap())),
                ));
                patterns.push((
                    p118,
                    self.process_surface(&Array1::from_iter(p118))
                        .unwrap_or(Array1::from_elem(3, T::from_f32(0.2).unwrap())),
                ));
            }
            Triads::Augmented => {
                // Augmented triads have symmetric stability
                patterns.push((
                    p811,
                    self.process_surface(&Array1::from_iter(p811))
                        .unwrap_or(Array1::from_elem(3, T::from_f32(0.5).unwrap())),
                ));
                patterns.push((
                    p181,
                    self.process_surface(&Array1::from_iter(p181))
                        .unwrap_or(Array1::from_elem(3, T::from_f32(0.5).unwrap())),
                ));
                patterns.push((
                    p118,
                    self.process_surface(&Array1::from_iter(p118))
                        .unwrap_or(Array1::from_elem(3, T::from_f32(0.5).unwrap())),
                ));
            }
        }

        // Add balanced distribution
        patterns.push((
            [T::from_f32(1.0 / 3.0).unwrap(); 3],
            self.process_surface(&Array1::<T>::from_elem(3, T::from_f32(1.0 / 3.0).unwrap()))
                .unwrap_or(Array1::from_elem(3, p5)),
        ));

        Some(patterns)
    }
    /// Get surface network parameters
    pub fn get_surface_parameters(&self) -> (T, T, T) {
        let config = if let Some(surface) = &self.surface {
            *surface.model().config()
        } else {
            crate::surface::SurfaceModelConfig::default() // Default parameters
        };
        (*config.momentum(), *config.decay(), *config.learning_rate())
    }
    /// Identify a critical point in the tonal space
    pub fn identify_critical_point(&mut self, name: &str, pitch: usize) {
        self.critical_points.insert(name.to_string(), pitch.pmod());
    }
    /// Initialize the surface network for behavior learning
    #[cfg(not(feature = "rand"))]
    pub fn init_surface(&mut self) -> crate::Result<()> {
        if self.surface.is_none() {
            let headspace = *self.driver.headspace();
            let surface = SurfaceNetwork::new(headspace).init();
            self.surface = Some(surface);
            self.prev_weight_changes = Some((
                Array2::zeros((5, 3)), // Default size for primary weights
                Array2::zeros((1, 5)), // Default size for secondary weights
            ));
        }
        Ok(())
    }
    #[cfg(feature = "rand")]
    pub fn init_surface(&mut self) -> crate::Result<()>
    where
        rand_distr::StandardNormal: rand_distr::Distribution<T>,
    {
        if self.surface.is_none() {
            let headspace = self.driver.headspace().clone();
            let surface = SurfaceNetwork::new(headspace).init();
            self.surface = Some(surface);
            self.prev_weight_changes = Some((
                Array2::zeros((5, 3)), // Default size for primary weights
                Array2::zeros((1, 5)), // Default size for secondary weights
            ));
        }
        Ok(())
    }
    /// Integrate knowledge from another node
    pub fn integrate_external_knowledge(
        &mut self,
        patterns: &[Vec<usize>],
        source_id: &EdgeId,
    ) -> crate::Result<()>
    where
        T: core::fmt::Display + core::str::FromStr,
    {
        // 1. Store patterns in topological memory
        let mut adaptation_count = 0;
        for pattern in patterns {
            // Skip empty patterns
            if pattern.is_empty() {
                continue;
            }

            // For surface weights, integrate them into our surface network
            if pattern.len() >= 3 && pattern[0] == 999 {
                // This is a weight pattern, process it with adapt_surface_to_external_patterns
                adaptation_count += 1;
            } else {
                // Regular pattern, store in memory
                // Add source information
                let mut content = Vec::with_capacity(pattern.len() + 2);
                content.push(998); // Marker for external pattern
                content.push(**source_id); // Source ID
                content.extend_from_slice(pattern);

                self.store.create_feature(2, content);
            }
        }

        // 2. If we have enough surface patterns and a surface network, apply them
        if adaptation_count > 0 && self.has_surface_network() {
            // Filter out just the surface patterns
            let surface_pattern_iter = patterns.iter().cloned().filter_map(|p| {
                if p.len() >= 3 && p[0] == 999 {
                    return Some(p);
                }
                None
            });

            self.adapt_surface_to_external_patterns(surface_pattern_iter)?;

            // Update learning metrics
            let current_accuracy = self.get_learning_accuracy();
            self.store.set_property(
                "learning_accuracy",
                format!(
                    "{}",
                    (current_accuracy * T::from_f32(0.9).unwrap()
                        + T::from_f32(0.6).unwrap() * T::from_f32(0.1).unwrap())
                ),
            );
        }

        Ok(())
    }
    /// Learn headspace based on its structure and critical points
    pub fn learn_headspace(&mut self) -> crate::Result<()> {
        let triad = self.driver().headspace();
        let notes = triad.notes();

        // Define relationships between notes in the triad
        // (index1, index2, strength)
        let mut relationships = Vec::new();

        // Root-third relationship
        let root_third_strength = match triad.class() {
            Triads::Major => 0.8, // Strong in major
            Triads::Minor => 0.7, // Slightly less strong in minor
            _ => 0.6,
        };
        relationships.push((0, 1, T::from_f32(root_third_strength).unwrap()));

        // Third-fifth relationship
        let third_fifth_strength = match triad.class() {
            Triads::Diminished => 0.6, // Weaker in diminished
            _ => 0.75,
        };
        relationships.push((1, 2, T::from_f32(third_fifth_strength).unwrap()));

        // Fifth-root relationship (complete the cycle)
        let fifth_root_strength = match triad.class() {
            Triads::Augmented => 0.65,  // Weaker in augmented
            Triads::Diminished => 0.65, // Weaker in diminished
            _ => 0.7,
        };
        relationships.push((2, 0, T::from_f32(fifth_root_strength).unwrap()));

        // Learn these relationships
        self.store
            .learn_headspace_relationships(&notes, &relationships);

        Ok(())
    }
    /// Learn a pattern from inputs within current headspace
    pub fn learn_pattern<X, Y, Z>(
        &mut self,
        inputs: &X,
        targets: &Y,
        iterations: usize,
    ) -> crate::Result<()>
    where
        SurfaceModel<T>: Train<X, Y, Output = Z>,
    {
        // Train surface network with ndarray types
        let surface = self
            .surface
            .as_mut()
            .ok_or(crate::ActorError::NotInitialized(
                "surface network hasn't been initialized yet...".to_string(),
            ))?;
        surface.train_for(inputs, targets, iterations)?;
        Ok(())
    }
    /// Learn stability characteristics specific to the current chord class
    pub fn learn_stability_characteristics(&mut self) -> crate::Result<()>
    where
        D: TriadDriver,
    {
        // Create patterns appropriate for the current chord class
        let _patterns = self.create_stability_patterns_for_class(self.class());
        todo!("update stability learning");

        // // Extract inputs and targets for training
        // let mut training_inputs = Array2::zeros((patterns.len(), 3));
        // let mut training_targets = Array1::zeros(patterns.len());
        // for (i, (input, target)) in patterns.iter().enumerate() {
        //     training_inputs.row_mut(i).assign(&Array1::from_vec(input.to_vec()));
        //     training_targets[[i]] = *target;
        // }
        // // Learn the stability patterns with multiple iterations for reinforcement
        // if !training_inputs.is_empty() {
        //     self.learn_pattern(&training_inputs, &training_targets.insert_axis(Axis(1)), 200)?;
        // }

        // // Record that this node has learned its own stability characteristics
        // // Note: This is useful for tracking which nodes have been trained
        // let chord_class_code = match self.class() {
        //     TriadClass::Major => 0,
        //     TriadClass::Minor => 1,
        //     TriadClass::Diminished => 2,
        //     TriadClass::Augmented => 3,
        // };
        // self.store
        //     .record_event("learned_stability", Some(vec![chord_class_code]));

        // Ok(())
    }
    /// Learn stability patterns from other nodes
    pub fn learn_stability_patterns(
        &mut self,
        _patterns: &[StabilityPattern],
    ) -> crate::Result<()> {
        todo!("update pattern learning ");
    }
    /// Learn the surface defined by critical points
    pub fn learn_surface(&mut self) -> crate::Result<()> {
        let tonic = self.get_tonic();

        // Learn the surface based on critical points
        self.store
            .learn_surface(&self.critical_points, tonic.class());

        // Now additionally learn parameters between critical points
        self.interpolate_surface_between_critical_points();

        Ok(())
    }
    /// Learn a transformation sequence
    pub fn learn_transformation_sequence(&mut self, transforms: &[LPR]) -> crate::Result<()> {
        // Convert LPR sequence to usize values
        let sequence: Vec<usize> = transforms.iter().map(|&lpr| lpr.into()).collect();

        // Record in memory with medium importance
        self.store.record_pattern(&sequence);

        Ok(())
    }
    /// Navigate to satisfy a specific critical point
    pub fn navigate_to_critical_point(&mut self, point_name: &str) -> crate::Result<Vec<LPR>>
    where
        D: TriadDriver,
    {
        // Get critical points
        let target_point = match self.critical_points.get(point_name) {
            Some(&point) => point,
            None => return Err(crate::ActorError::InvalidCriticalPoint),
        };

        // Current position
        let _headspace = *self.driver().headspace();

        // Try to find existing navigation path in memory
        let path = self.find_path_to_point(target_point);

        if let Some(transforms) = path {
            // Execute the transforms
            self.transform_batch(&transforms)?;

            // Learn from successful navigation
            // self.learn_from_navigation(current_triad.clone(), &transforms, target_point);

            return Ok(transforms);
        }

        // If no path found, use motion planning to get there
        let transform_path = self.plan_motion_to_point(target_point)?;

        if !transform_path.is_empty() {
            // Execute the transforms
            self.transform_batch(&transform_path)?;

            // Learn from this navigation
            // self.learn_from_navigation(current_triad.clone(), &transform_path, target_point);
            todo!("learn from navigation");
        }

        Ok(transform_path)
    }
    /// Optimize memory usage with intelligent feature management
    pub fn optimize_memory(
        &mut self,
        max_features: usize,
    ) -> crate::Result<super::VirtualMemoryAnalysis<T>> {
        // Get memory statistics before optimization
        let stats_before = self.store.get_statistics();

        // STEP 1: Identify knowledge importance by usage and recency
        // Calculate importance thresholds based on memory pressure
        let current_feature_count = self.total_features();
        let memory_pressure = (current_feature_count as f32) / (max_features as f32);

        // Adjust pruning threshold based on memory pressure
        let importance_threshold = if memory_pressure > 1.5 {
            // High memory pressure - be more aggressive (keep only very important features)
            0.6
        } else if memory_pressure > 1.0 {
            // Moderate pressure - normal pruning
            0.4
        } else {
            // Low pressure - conservative pruning (just remove clearly unimportant features)
            0.2
        };
        let memory_pressure = T::from_f32(memory_pressure).unwrap();
        let importance_threshold = T::from_f32(importance_threshold).unwrap();

        // STEP 2: Consolidate similar features to reduce redundancy
        let similarity_threshold = T::from_f32(0.75).unwrap(); // Features with 75% similarity can be merged
        self.consolidate_similar_patterns(similarity_threshold)?;

        // STEP 3: Protect features related to critical points
        let mut protected_features = std::collections::HashSet::new();

        // Protect features related to critical points in tonal space
        for &pitch in self.critical_points.values() {
            // Find features containing this pitch class
            for feature in self.store.features() {
                if feature.contains(&pitch) && feature.importance() >= &T::from_f32(0.3).unwrap() {
                    protected_features.insert(feature.id());
                }
            }
        }

        // STEP 4: Prune low-importance features, respecting protected features
        let feature_ids_to_prune: Vec<_> = self
            .store
            .features()
            .iter()
            .filter(|f| {
                f.importance() < &importance_threshold
                    && !protected_features.contains(&f.id())
                    && f.death().is_none()
            })
            .map(|f| f.id())
            .collect();
        let pruned_count = feature_ids_to_prune.len();
        for id in feature_ids_to_prune {
            self.store.prune_feature(id);
        }

        // STEP 5: Compact memory to remove dead features
        self.store.compact();

        // STEP 6: Rebuild any specialized indices not covered by compact()
        // If we have any custom indexing needs:
        if current_feature_count > 1000 {
            // For large memory stores, ensure topological relationships are optimized
            self.store.rebuild_indices();
        }

        // STEP 7: Optimize relationships between remaining features
        self.store.optimize();

        // Get memory statistics after optimization
        let stats_after = self.store.get_statistics();

        // Return statistics about the optimization process
        Ok(super::VirtualMemoryAnalysis {
            features_before: stats_before.total_features(),
            features_after: stats_after.total_features(),
            pruned_count,
            memory_pressure,
            importance_threshold,
        })
    }
    /// Predict the next likely transformation based on patterns in memory
    pub fn predict_next_transformation(&self) -> Option<LPR> {
        let discovery = self.store.find_by_dimension(1);
        // Get recent transformation features (dimension 1)
        let recent_transforms = discovery
            .iter()
            .filter(|f| f.is_alive())
            .collect::<Vec<_>>();

        if recent_transforms.len() < 2 {
            return None;
        }

        // Extract transformation types (LPR values)
        let transform_sequence = recent_transforms
            .iter()
            .rev() // Most recent first
            .take(5) // Look at last 5 transformations
            .filter_map(|f| {
                if f.content_len() > 6 {
                    // Last element is the transform type
                    Some(f[6])
                } else {
                    None
                }
            })
            .collect::<Vec<_>>();

        // Find patterns matching this sequence
        let patterns = self.store.find_matching_patterns(&transform_sequence);

        if patterns.is_empty() {
            return None;
        }

        // Sort by importance
        let mut sorted_patterns = patterns.clone();
        sorted_patterns.sort_by(|a, b| {
            b.importance()
                .partial_cmp(a.importance())
                .unwrap_or(core::cmp::Ordering::Equal)
        });

        // Get the most important pattern
        let best_pattern = &sorted_patterns[0];

        // If the pattern suggests a next move
        if best_pattern.sequence_len() > transform_sequence.len() {
            // Get the predicted next move
            let next_move = best_pattern[transform_sequence.len()];

            // Convert usize back to LPR
            match next_move {
                0 => Some(LPR::Leading),
                1 => Some(LPR::Parallel),
                2 => Some(LPR::Relative),
                _ => None,
            }
        } else {
            None
        }
    }
    /// Process a message from another node
    pub fn process_message(&mut self, source: EdgeId, message: &[u8]) -> crate::Result<()> {
        self.operator
            .active_operator_mut::<D>()
            .process_message(source, message, &mut self.store)
    }
    /// Process an input through the surface network to predict behavior
    pub fn process_surface<X, Y>(&self, input: &X) -> crate::Result<Y>
    where
        SurfaceModel<T>: Predict<X, Output = Y>,
    {
        // Ensure the surface network is initialized

        if let Some(surface) = &self.surface {
            // Process the input through the surface network
            let output = surface.predict(input)?;
            Ok(output)
        } else {
            Err(crate::ActorError::NotInitialized(
                "Surface network not initialized".to_string(),
            ))
        }
    }
    /// Have the active operator propose a transformation (if supported)
    pub fn propose_transformation(&self) -> Option<LPR> {
        match &self.operator {
            Operator::Agent(agent) => {
                Some(agent.propose_transformation(&self.driver, &self.store)?)
            }
            _ => None, // Observer doesn't propose transformations
        }
    }
    /// Get the resource requirements for this node
    pub fn resource_requirements(&self) -> (usize, usize) {
        let (actor_mem, actor_compute) = self
            .operator()
            .active_operator::<D>()
            .resource_requirements();

        // Add memory system requirements
        let memory_usage = self.store.count_features() * 10; // 10 units per feature

        // Add plant requirements
        let plant_memory = 50; // Base memory for plant

        // Total resources (memory, compute)
        (actor_mem + memory_usage + plant_memory, actor_compute)
    }
    /// Prune low-importance features
    pub fn prune_low_importance_features(&mut self, threshold: T) -> crate::Result<()> {
        // Get IDs of features to prune
        let to_prune: Vec<_> = self
            .store()
            .features()
            .iter()
            .filter_map(|f| {
                if f.death().is_none() && f.importance() < &threshold {
                    return Some(f.id());
                }
                None
            })
            .collect();

        // Prune features
        for id in to_prune {
            self.store_mut().prune_feature(id);
        }

        Ok(())
    }
    /// Set the name of the node
    pub fn set_name(&mut self, name: &str) {
        // Store name in memory as a property
        self.store.set_property("name", name);
    }
    /// Share patterns with another node
    pub fn share_patterns<E>(&self, target: &mut VNode<E, T>) -> crate::Result<()>
    where
        E: Driver<Triad>,
    {
        // Only share if both nodes allow it
        let self_allows = self
            .operator()
            .active_operator::<D>()
            .allows_pattern_sharing();

        let target_allows = target
            .operator()
            .active_operator::<E>()
            .allows_pattern_sharing();

        if !self_allows || !target_allows {
            return Ok(());
        }

        // Get patterns from this node's memory
        for pattern in self.store.patterns() {
            // Only share significant patterns
            if pattern.importance() > &T::from_f32(0.5).unwrap() {
                target.store_mut().record_pattern_with_importance(
                    pattern.sequence(),
                    *pattern.importance() * T::from_f32(0.9).unwrap(), // Slight decay when sharing
                );
            }
        }

        Ok(())
    }
    /// Train the surface network on a pattern
    #[cfg(not(feature = "rand"))]
    pub fn train_surface<X, Y, Z>(&mut self, inputs: &X, targets: &Y) -> crate::Result<Z>
    where
        T: core::fmt::Debug + Send + Sync + num_traits::Signed + rustfft::FftNum,
        SurfaceModel<T>: Train<X, Y, Output = Z>,
    {
        // Ensure the surface network is initialized
        self.ensure_surface_network()?;

        if let Some(surface) = &mut self.surface {
            // Train the surface network with the provided inputs and targets
            let output = surface.train(inputs, targets)?;
            Ok(output)
        } else {
            Err(crate::ActorError::NotInitialized(
                "Surface network not initialized".to_string(),
            ))
        }
    }
    /// Train the surface network on a pattern
    #[cfg(feature = "rand")]
    pub fn train_surface<X, Y, Z>(&mut self, inputs: &X, targets: &Y) -> crate::Result<Z>
    where
        T: core::fmt::Debug + Send + Sync + num_traits::Signed + rustfft::FftNum,
        SurfaceModel<T>: Train<X, Y, Output = Z>,
        rand_distr::StandardNormal: rand_distr::Distribution<T>,
    {
        // Ensure the surface network is initialized
        self.ensure_surface_network()?;

        if let Some(surface) = &mut self.surface {
            // Train the surface network with the provided inputs and targets
            let output = surface.train(inputs, targets)?;
            Ok(output)
        } else {
            Err(crate::ActorError::NotInitialized(
                "Surface network not initialized".to_string(),
            ))
        }
    }
    /// Apply a transformation to the plant and record in memory
    pub fn transform(&mut self, transform: LPR) -> crate::Result<()>
    where
        D: TriadDriver,
    {
        // First check if the operator accepts this transformation
        let accepted = match &mut self.operator {
            Operator::Observer(observer) => {
                observer.process_transform(transform, &mut self.driver, &mut self.store)?
            }
            Operator::Agent(agent) => {
                agent.process_transform(transform, &mut self.driver, &mut self.store)?
            }
        };

        if !accepted {
            return Err(crate::ActorError::TransformationError);
        }

        // Capture current state
        let from_notes = self.get_notes();
        let from_class = self.class();

        // Apply transformation
        self.driver.transform(transform)?;

        // Record transformation in memory
        self.store.record_transformation(
            from_notes,
            from_class,
            transform,
            self.get_notes(),
            self.class(),
        );

        // Update tonic history
        let tonic = self.get_tonic();
        self.tonic_history.push(tonic.class());

        // Advance time in memory
        self.store.next_epoch();

        // Invalidate cached context
        self.last_context = None;

        Ok(())
    }
    /// Efficiently apply multiple transformations in batch
    pub fn transform_batch(&mut self, transforms: &[LPR]) -> crate::Result<()>
    where
        D: TriadDriver,
    {
        // Pre-allocate with capacity instead of growing dynamically
        let mut transform_data = Vec::with_capacity(transforms.len());
        let mut tonic_history = Vec::with_capacity(transforms.len() + 1);

        if transforms.is_empty() {
            return Ok(());
        }

        // Check each transform with the operator
        for &transform in transforms {
            let accepted = match &mut self.operator {
                Operator::Observer(observer) => {
                    observer.process_transform(transform, &mut self.driver, &mut self.store)?
                }
                Operator::Agent(agent) => {
                    agent.process_transform(transform, &mut self.driver, &mut self.store)?
                }
            };

            if !accepted {
                return Err(crate::ActorError::TransformationError);
            }
        }

        // Collect state information before transforms
        let original_notes = self.get_notes();
        let original_class = self.class();

        // Prepare batch data
        tonic_history.push(self.get_tonic());

        // Current state tracking
        let mut current_notes = original_notes;
        let mut current_class = original_class;
        let mut current_triad = *self.driver().headspace();

        // Process each transformation
        for &transform in transforms {
            // Apply the transformation to our tracking variables
            let next_triad = current_triad.transform(transform);
            let next_notes = next_triad.notes();
            let next_class = next_triad.class();
            let octave = next_triad.octave();

            // Record transformation data
            transform_data.push((
                current_notes,
                current_class,
                transform,
                next_notes,
                next_class,
            ));

            // Update current state
            current_notes = next_notes;
            current_class = next_class;
            current_triad = next_triad;

            // Calculate tonic for the new state
            let root = Aspn::new(current_triad.root(), octave);
            tonic_history.push(root);
        }

        // Actually apply all transformations to the plant
        self.driver_mut().walk(transforms)?;

        // Record all transformations in memory at once
        self.store_mut()
            .record_transformations_batch(transform_data);

        // Update tonic history
        self.tonic_history
            .extend(tonic_history.into_iter().skip(1).map(|t| t.class()));

        // Advance time in memory
        self.store_mut().next_epoch();

        // Invalidate cached context
        self.last_context = None;

        Ok(())
    }
    /// Update the surface network when the headspace changes
    pub fn update_surface_headspace(&mut self) -> crate::Result<()> {
        let headspace = *self.driver().headspace();
        if let Some(surface) = &mut self.surface {
            surface.reconfigure(headspace);
        }
        Ok(())
    }
}

impl<D, T> VNode<D, T>
where
    D: RawDriver<Triad>,
    T: Float + FromPrimitive + ScalarOperand,
{
    /// Find a path to a point using memory and learning
    pub(crate) fn find_path_to_point(&self, target_point: usize) -> Option<Vec<LPR>> {
        // Check for direct paths in memory
        let current_notes = self.driver().headspace().notes();
        // TODO: integrate with pre-existing methods to reduce the amount of excess code
        // let _path_to_target = self
        //     .driver()
        //     .headspace()
        //     .path_finder()
        //     .find_paths_to_target(target_point);

        // Look for navigation features that lead to target
        let nav_features = self
            .store
            .features()
            .iter()
            .filter(|f| {
                f.dimension() == 2 && // Navigation features
                f.is_alive() &&
                f.content().len() > current_notes.len() &&
                f.content()[0..current_notes.len()] == current_notes &&
                f.content()[current_notes.len()..].contains(&target_point)
            })
            .collect::<Vec<_>>();

        if nav_features.is_empty() {
            return None;
        }

        // Sort by importance
        let mut sorted_nav = nav_features.clone();
        sorted_nav.sort_by(|a, b| {
            b.importance()
                .partial_cmp(a.importance())
                .unwrap_or(core::cmp::Ordering::Equal)
        });

        // Extract the navigation path from the best feature
        let best_nav = &sorted_nav[0];

        // Try to reconstruct the transform sequence
        // This is simplified - in a full implementation we'd need to store the actual transforms
        let path_hash = best_nav.content().last().cloned()?;
        let mut transforms = Vec::new();
        let mut hash = path_hash;

        while hash > 0 {
            let transform_id = hash % 3;
            hash /= 3;

            let transform = LPR::from(transform_id);

            transforms.push(transform);
        }

        transforms.reverse();

        if transforms.is_empty() {
            None
        } else {
            Some(transforms)
        }
    }
    /// generate context for the node
    pub(crate) fn generate_context(&self) -> crate::Result<ActorContext<T>>
    where
        T: core::iter::Sum + NumAssign,
    {
        self.operator()
            .active_operator()
            .contextualize(&self.driver, &self.store)
    }
    /// Interpolate parameters between critical points
    pub(crate) fn interpolate_surface_between_critical_points(&mut self) {
        // For each pair of critical points, create intermediate parameters
        for (name_i, point_i) in &self.critical_points {
            for (name_j, point_j) in &self.critical_points {
                if name_i >= name_j {
                    continue;
                } // Skip duplicates

                // Calculate distance between points (in pitch class space)
                let raw_dist = ((*point_j as isize) - (*point_i as isize)).pmod();
                let distance = core::cmp::min(raw_dist, 12 - raw_dist) as usize;

                // Skip if too far apart
                if distance > 3 {
                    continue;
                }

                // Create interpolated parameters
                for k in 1..distance {
                    // Calculate interpolated position
                    let position = (*point_i + k).pmod();

                    // Calculate interpolated value
                    let t = k as f32 / distance as f32;
                    let value = 0.5 - (t - 0.5).abs(); // Peaked at midpoint

                    // Store the interpolated parameter
                    self.store
                        .learn_surface_parameter(vec![position], T::from_f32(value).unwrap());
                }
            }
        }
    }
    /// Plan motion to a point using transformations
    pub(crate) fn plan_motion_to_point(&self, target_point: usize) -> crate::Result<Vec<LPR>> {
        let paths = self
            .driver()
            .headspace()
            .path_finder()
            .find_paths_to_target(target_point);

        match paths.first() {
            Some(chain) => {
                // If we found a path, return it
                Ok(chain.path().clone())
            }
            None => {
                // If no path found, return an empty vector
                Err(crate::ActorError::no_path_found(
                    self.driver().headspace(),
                    target_point,
                ))
            }
        }
    }

    // Learn from a successful navigation
    // fn learn_from_navigation(&mut self, start_triad: Triad, path: &[LPR], target_point: usize) {
    //     // Record the navigation path
    //     self.store
    //         .record_navigation(start_triad.notes(), self.get_notes(), path);
    //     // Calculate reward based on how close we got to target
    //     let distance = self.distance_to_point(target_point);
    //     // Get the driver to learn from this
    //     let driver = &mut self.plant;
    //     let reward = if distance == 0 {
    //         1.0 // Perfect match
    //     } else {
    //         T::from_f32(0.8).unwrap() - (distance as f32 * T::from_f32(0.1).unwrap()) // Diminishing reward with distance
    //     };

    //     // Learn from this execution sequence
    //     driver.learn_from_execution(&mut self.store, path.len(), reward);
    // }
}
