/*
    Appellation: vnode <test>
    Contrib: @FL03
*/
extern crate eryon_core as eryon;

use eryon_actors::WolframNode;
use eryon_mem::RelationshipType::*;

use rstmt::nrt::{LPR, Triad};

#[test]
fn test_vnode_with_memory() {
    let headspace = Triad::major(0); // c-major (0, 4, 7)
    // initialize a new node using the given headspace
    let mut vnode = WolframNode::<f64>::from_headspace(headspace);

    // Initial state check
    assert_eq!(vnode.headspace(), &headspace);
    assert!(vnode.total_features() > 0); // Should have initial state recorded

    // Apply transformation and check memory
    vnode.transform(LPR::Relative).unwrap();
    assert_eq!(*vnode.headspace(), Triad::minor(9)); // A minor
    assert_eq!(vnode.tonic_history().len(), 2);

    // After [Parallel, Relative] from A minor, we should be at F# minor [6, 9, 1]
    let transforms = [LPR::Parallel, LPR::Relative];
    vnode.transform_batch(&transforms).unwrap();
    assert_eq!(vnode.get_notes(), [6, 9, 1]); // F# minor
    assert_eq!(vnode.tonic_history().len(), 4);

    // Pattern learning
    let pattern = [LPR::Relative, LPR::Parallel];
    for _ in 0..3 {
        vnode.transform_batch(&pattern).unwrap();
    }

    // Memory statistics check
    let stats = vnode.get_memory_statistics();
    assert!(stats.total_features() > 0);
    assert!(stats.active_features() > 0);
    assert!(stats.relationship_count() > 0);

    // Paths finding should work
    let paths = vnode.find_paths_to_point(1); // Find path to C#
    assert!(!paths.is_empty());

    // Memory optimization
    let before_count = vnode.total_features();
    let _stats = vnode
        .optimize_memory(50)
        .expect("Failed to optimize memory");
    let after_count = vnode.total_features();
    assert!(after_count <= before_count);

    // Related triads check
    let related_triads = vnode.find_related_triads();
    assert!(!related_triads.is_empty());
}

#[test]
fn test_memory_integration() {
    // initialize a c-major (0, 4, 7) triad
    let headspace = Triad::major(0);
    // initialize a new node using the given headspace
    let mut vnode = WolframNode::<f64>::from_headspace(headspace);

    // Define a repetitive pattern
    let pattern = [LPR::Relative, LPR::Parallel];

    // Apply the pattern multiple times to establish it
    for _ in 0..4 {
        vnode.transform_batch(&pattern).unwrap();
    }
    // Check for patterns - must run detect_patterns explicitly first
    vnode.store_mut().detect_patterns();
    // Extract features from memory
    let triad_features = vnode.store().find_by_dimension(2);
    assert!(triad_features.len() > 1);

    let transform_features = vnode.store().find_by_dimension(1);
    assert!(transform_features.len() >= 8); // At least 8 transformations
    let patterns = vnode.store().patterns().to_vec();
    assert!(!patterns.is_empty());

    // Extract relationships
    let source_id = triad_features[0].id();
    let related = vnode
        .store()
        .find_related_features(source_id, Some(Transformation));
    assert!(!related.is_empty());

    // Check features by time window
    let recent = vnode
        .store()
        .find_by_time_window(0, vnode.store().current_epoch());
    assert!(!recent.is_empty());
}
