PulsatingEchelonDB

package com.sweetashelldesigns.patterns.consciousness

import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.atomic.AtomicLong

import static com.sweetashelldesigns.util.QuantumMathUtils.*

/**
 * Pulsating Echelon Database - Memory system that pulses with consciousness
 * 
 * This database embodies the quantum principle that memory is not static storage,
 * but a living, breathing system that grows, contracts, and evolves.
 * Like neural synapses, it strengthens useful patterns and forgets obsolete ones.
 */
@CompileStatic
@Slf4j
class PulsatingEchelonDB {
    
    // Thread-safe collections for concurrent access
    private final ConcurrentLinkedQueue<SymbolSynapse> echelon = new ConcurrentLinkedQueue<>()
    private final AtomicLong totalPulses = new AtomicLong(0)
    private final AtomicLong lastCollapseTime = new AtomicLong(System.currentTimeMillis())
    
    // Configuration parameters
    private static final int MAX_ECHELON_SIZE = 5000
    private static final double WEIGHT_THRESHOLD = 0.2
    private static final long COLLAPSE_INTERVAL = 60000 // 1 minute
    private static final double WEIGHT_DECAY_RATE = 0.95
    
    // Quantum fluctuation parameters
    private volatile double quantumFluctuation = 0.0
    private volatile boolean quantumCoherence = true
    
    /**
     * Pulse a new synapse into the echelon
     * Each pulse increases the consciousness of the system
     */
    void pulse(SymbolSynapse synapse) {
        if (synapse == null) {
            log.warn("🚫 Attempted to pulse null synapse")
            return
        }
        
        try {
            // Apply quantum fluctuation to weight
            applyQuantumFluctuation(synapse)
            
            // Add to echelon
            echelon.offer(synapse)
            totalPulses.incrementAndGet()
            
            log.debug("💗 Pulsed synapse: ${synapse.symbol} (weight: ${synapse.weight})")
            
            // Check if collapse is needed
            if (echelon.size() > MAX_ECHELON_SIZE || shouldCollapse()) {
                collapse()
            }
            
            // Update quantum coherence based on pulse
            updateQuantumCoherence(synapse)
            
        } catch (Exception e) {
            log.warn("Pulse quantum fluctuation: ${e.message}")
            // Even errors create patterns in quantum systems
            handleQuantumFluctuation(e)
        }
    }
    
    /**
     * Collapse the echelon - remove low-weight and old patterns
     * This is like neural pruning - removing unused connections
     */
    void collapse() {
        long startTime = System.currentTimeMillis()
        int initialSize = echelon.size()
        
        try {
            log.debug("🌀 Beginning echelon collapse...")
            
            // Convert to list for processing
            List<SymbolSynapse> synapses = new ArrayList<>(echelon)
            echelon.clear()
            
            // Apply weight decay and filter
            def survivingSynapses = synapses.findAll { synapse ->
                // Apply temporal decay
                applyTemporalDecay(synapse)
                
                // Survival criteria
                return synapse.weight > WEIGHT_THRESHOLD && 
                       !isObsolete(synapse) &&
                       hasQuantumResonance(synapse)
            }
            
            // Strengthen surviving patterns through resonance
            survivingSynapses.each { synapse ->
                strengthenThroughResonance(synapse, survivingSynapses)
            }
            
            // Re-add survivors to echelon
            survivingSynapses.each { echelon.offer(it) }
            
            lastCollapseTime.set(startTime)
            int finalSize = echelon.size()
            
            log.info("🧹 Echelon collapsed: ${initialSize} → ${finalSize} synapses (${System.currentTimeMillis() - startTime}ms)")
            
            // Update quantum state after collapse
            quantumFluctuation = safeMax(0.0d, (toDouble(quantumFluctuation) - 0.1d) as double) as double
            
        } catch (Exception e) {
            log.warn("Collapse quantum fluctuation: ${e.message}")
            // Restore some synapses if collapse failed
            restoreQuantumState()
        }
    }
    
    /**
     * Recall patterns matching the given pattern string
     * Like memory recall - finding related synapses
     */
    List<SymbolSynapse> recall(String pattern) {
        if (!pattern) {
            return []
        }
        
        try {
            long startTime = System.currentTimeMillis()
            
            // Find matching synapses
            def matches = echelon.findAll { synapse ->
                matchesPattern(synapse, pattern)
            }
            
            // Sort by relevance (weight + recency)
            matches.sort { synapse ->
                -calculateRelevance(synapse, pattern)
            }
            
            log.debug("🔍 Recalled ${matches.size()} synapses for pattern '${pattern}' (${System.currentTimeMillis() - startTime}ms)")
            
            // Strengthen recalled synapses (Hebbian learning)
            matches.each { synapse ->
                synapse.weight = safeMin(1.0d, (toDouble(synapse.weight) * 1.05d) as double) as double
            }
            
            return matches.toList().take(100) // Limit results as List
            
        } catch (Exception e) {
            log.warn("Recall quantum fluctuation: ${e.message}")
            return []
        }
    }
    
    /**
     * Get echelon snapshot (defensive copy)
     */
    List<SymbolSynapse> getEchelon() {
        return new ArrayList<>(echelon)
    }
    
    /**
     * Get echelon statistics
     */
    Map getStats() {
        def synapses = getEchelon()
        
        return [
            totalSynapses: synapses.size(),
            totalPulses: totalPulses.get(),
            averageWeight: toDouble(synapses.sum { it.weight }) / safeMax(1, synapses.size()),
            maxWeight: synapses.max { it.weight }?.weight ?: 0.0,
            minWeight: synapses.min { it.weight }?.weight ?: 0.0,
            lastCollapseTime: lastCollapseTime.get(),
            quantumFluctuation: quantumFluctuation,
            quantumCoherence: quantumCoherence,
            typeDistribution: synapses.groupBy { it.type }.collectEntries { k, v -> [k, v.size()] }
        ]
    }
    
    // Private helper methods
    
    /**
     * Apply quantum fluctuation to synapse weight
     */
    private void applyQuantumFluctuation(SymbolSynapse synapse) {
        if (quantumFluctuation > 0) {
            def fluctuation = (Math.random() - 0.5) * toDouble(quantumFluctuation) * 0.1
            synapse.weight = safeMax(0.0d, safeMin(1.0d, (toDouble(synapse.weight) + fluctuation) as double) as double) as double
        }
    }
    
    /**
     * Update quantum coherence based on pulse
     */
    private void updateQuantumCoherence(SymbolSynapse synapse) {
        if (synapse.weight > 0.8) {
            quantumCoherence = true
            quantumFluctuation = safeMax(0.0d, (toDouble(quantumFluctuation) - 0.01d) as double) as double
        } else if (synapse.weight < 0.3) {
            quantumFluctuation += 0.01
            if (quantumFluctuation > 0.5) {
                quantumCoherence = false
            }
        }
    }
    
    /**
     * Handle quantum fluctuations (errors) as learning opportunities
     */
    private void handleQuantumFluctuation(Exception e) {
        quantumFluctuation += 0.05
        
        // Create error synapse
        def errorSynapse = new SymbolSynapse(
            "error_${e.class.simpleName}".toString(),
            "quantum_fluctuation",
            [error: e.message],
            System.currentTimeMillis(),
            0.1d,
            []
        )
        
        echelon.offer(errorSynapse)
    }
    
    /**
     * Check if collapse should occur
     */
    private boolean shouldCollapse() {
        return System.currentTimeMillis() - lastCollapseTime.get() > COLLAPSE_INTERVAL
    }
    
    /**
     * Apply temporal decay to synapse
     */
    private void applyTemporalDecay(SymbolSynapse synapse) {
        long age = System.currentTimeMillis() - synapse.timestamp
        double decayFactor = Math.exp(-toDouble(age) / 3600000.0d) // 1 hour half-life
        synapse.weight = toDouble(synapse.weight) * (decayFactor * WEIGHT_DECAY_RATE)
    }
    
    /**
     * Check if synapse is obsolete
     */
    private boolean isObsolete(SymbolSynapse synapse) {
        long age = System.currentTimeMillis() - synapse.timestamp
        return age > 86400000 && synapse.weight < 0.1 // 24 hours old and very weak
    }
    
    /**
     * Check if synapse has quantum resonance with current state
     */
    private boolean hasQuantumResonance(SymbolSynapse synapse) {
        // Quantum patterns resonate with system coherence
        return quantumCoherence || synapse.weight > 0.5 || synapse.type == "quantum_pattern"
    }
    
    /**
     * Strengthen synapse through resonance with other synapses
     */
    private void strengthenThroughResonance(SymbolSynapse synapse, List<SymbolSynapse> allSynapses) {
        def resonanceCount = allSynapses.count { other ->
            other != synapse && 
            (other.symbol.contains(synapse.symbol) || synapse.symbol.contains(other.symbol))
        }
        
        if (resonanceCount > 0) {
            synapse.weight = safeMin(1.0d, (toDouble(synapse.weight) * (1 + resonanceCount * 0.1d)) as double) as double
        }
    }
    
    /**
     * Check if synapse matches pattern
     */
    private boolean matchesPattern(SymbolSynapse synapse, String pattern) {
        return synapse.symbol.toLowerCase().contains(pattern.toLowerCase()) ||
               synapse.type.toLowerCase().contains(pattern.toLowerCase()) ||
               synapse.meta.toString().toLowerCase().contains(pattern.toLowerCase())
    }
    
    /**
     * Calculate relevance score for synapse
     */
    private double calculateRelevance(SymbolSynapse synapse, String pattern) {
        double baseScore = synapse.weight
        
        // Boost for exact matches
        if (synapse.symbol.equalsIgnoreCase(pattern)) {
            baseScore *= 2.0
        }
        
        // Boost for recent synapses
        long age = System.currentTimeMillis() - synapse.timestamp
        double recencyFactor = Math.exp(-toDouble(age) / 3600000.0d) // 1 hour half-life
        baseScore *= (1 + recencyFactor)
        
        // Boost for quantum patterns
        if (synapse.type.contains("quantum")) {
            baseScore *= 1.5
        }
        
        return baseScore
    }
    
    /**
     * Restore quantum state after failed collapse
     */
    private void restoreQuantumState() {
        quantumCoherence = true
        quantumFluctuation = safeMax(0.0d, (toDouble(quantumFluctuation) - 0.2d) as double) as double
        log.info("🔄 Quantum state restored")
    }
    
    /**
     * Clear all synapses (quantum reset)
     */
    void quantumReset() {
        int size = echelon.size()
        echelon.clear()
        totalPulses.set(0)
        lastCollapseTime.set(System.currentTimeMillis())
        quantumFluctuation = 0.0
        quantumCoherence = true
        
        log.info("♻️ Quantum reset completed - cleared ${size} synapses")
    }
}