/**
 * Memory Class
 * 
 * Manages collective memory for the Hive Mind swarm,
 * providing persistent storage, retrieval, and learning capabilities.
 */

import { EventEmitter } from 'events';
import { performance } from 'perf_hooks';
import { DatabaseManager } from './DatabaseManager.js';
import { MCPToolWrapper } from '../integration/MCPToolWrapper.js';
import {
  MemoryEntry,
  MemoryNamespace,
  MemoryStats,
  MemorySearchOptions,
  MemoryPattern
} from '../types.js';

/**
 * High-performance LRU Cache with memory management
 */
class HighPerformanceCache<T> {
  private cache = new Map<string, { data: T; timestamp: number; size: number }>();
  private maxSize: number;
  private maxMemory: number;
  private currentMemory = 0;
  private hits = 0;
  private misses = 0;
  private evictions = 0;

  constructor(maxSize = 10000, maxMemoryMB = 100) {
    this.maxSize = maxSize;
    this.maxMemory = maxMemoryMB * 1024 * 1024;
  }

  get(key: string): T | undefined {
    const entry = this.cache.get(key);
    if (entry) {
      // Move to end (LRU)
      this.cache.delete(key);
      this.cache.set(key, entry);
      this.hits++;
      return entry.data;
    }
    this.misses++;
    return undefined;
  }

  set(key: string, data: T): void {
    const size = this.estimateSize(data);
    
    // Handle memory pressure
    while (this.currentMemory + size > this.maxMemory && this.cache.size > 0) {
      this.evictLRU();
    }

    // Handle size limit
    while (this.cache.size >= this.maxSize) {
      this.evictLRU();
    }

    this.cache.set(key, { data, timestamp: Date.now(), size });
    this.currentMemory += size;
  }

  private evictLRU(): void {
    const firstKey = this.cache.keys().next().value;
    if (firstKey) {
      const entry = this.cache.get(firstKey)!;
      this.cache.delete(firstKey);
      this.currentMemory -= entry.size;
      this.evictions++;
    }
  }

  private estimateSize(data: any): number {
    try {
      return JSON.stringify(data).length * 2; // Rough estimate
    } catch {
      return 1000; // Default size for non-serializable objects
    }
  }

  getStats() {
    const total = this.hits + this.misses;
    return {
      size: this.cache.size,
      memoryUsage: this.currentMemory,
      hitRate: total > 0 ? (this.hits / total) * 100 : 0,
      evictions: this.evictions,
      utilizationPercent: (this.currentMemory / this.maxMemory) * 100
    };
  }

  clear(): void {
    this.cache.clear();
    this.currentMemory = 0;
    this.hits = 0;
    this.misses = 0;
    this.evictions = 0;
  }

  has(key: string): boolean {
    return this.cache.has(key);
  }

  delete(key: string): boolean {
    const entry = this.cache.get(key);
    if (entry) {
      this.currentMemory -= entry.size;
      return this.cache.delete(key);
    }
    return false;
  }
}

/**
 * Memory pool for object reuse
 */
class ObjectPool<T> {
  private pool: T[] = [];
  private createFn: () => T;
  private resetFn: (obj: T) => void;
  private maxSize: number;
  private allocated = 0;
  private reused = 0;

  constructor(createFn: () => T, resetFn: (obj: T) => void, maxSize = 1000) {
    this.createFn = createFn;
    this.resetFn = resetFn;
    this.maxSize = maxSize;
  }

  acquire(): T {
    if (this.pool.length > 0) {
      this.reused++;
      return this.pool.pop()!;
    }
    this.allocated++;
    return this.createFn();
  }

  release(obj: T): void {
    if (this.pool.length < this.maxSize) {
      this.resetFn(obj);
      this.pool.push(obj);
    }
  }

  getStats() {
    return {
      poolSize: this.pool.length,
      allocated: this.allocated,
      reused: this.reused,
      reuseRate: this.allocated > 0 ? (this.reused / (this.allocated + this.reused)) * 100 : 0
    };
  }
}

export class Memory extends EventEmitter {
  private swarmId: string;
  private db: DatabaseManager;
  private mcpWrapper: MCPToolWrapper;
  private cache: HighPerformanceCache<any>;
  private namespaces: Map<string, MemoryNamespace>;
  private accessPatterns: Map<string, number>;
  private performanceMetrics: Map<string, number[]>;
  private objectPools: Map<string, ObjectPool<any>>;
  private isActive: boolean = false;
  private optimizationTimers: NodeJS.Timeout[] = [];
  private compressionThreshold = 10000; // 10KB
  private batchSize = 100;

  constructor(swarmId: string, options: {
    cacheSize?: number;
    cacheMemoryMB?: number;
    enablePooling?: boolean;
    compressionThreshold?: number;
    batchSize?: number;
  } = {}) {
    super();
    this.swarmId = swarmId;
    
    // Initialize high-performance cache
    this.cache = new HighPerformanceCache(
      options.cacheSize || 10000,
      options.cacheMemoryMB || 100
    );
    
    this.namespaces = new Map();
    this.accessPatterns = new Map();
    this.performanceMetrics = new Map();
    this.objectPools = new Map();
    
    if (options.compressionThreshold) {
      this.compressionThreshold = options.compressionThreshold;
    }
    
    if (options.batchSize) {
      this.batchSize = options.batchSize;
    }
    
    this.initializeNamespaces();
    
    if (options.enablePooling !== false) {
      this.initializeObjectPools();
    }
  }

  /**
   * Initialize optimized memory system
   */
  async initialize(): Promise<void> {
    const startTime = performance.now();
    
    this.db = await DatabaseManager.getInstance();
    this.mcpWrapper = new MCPToolWrapper();
    
    // Optimize database connection
    await this.optimizeDatabaseSettings();
    
    // Load existing memory entries with pagination
    await this.loadMemoryFromDatabase();
    
    // Start optimized memory management loops
    this.startOptimizedManagers();
    
    this.isActive = true;
    
    const duration = performance.now() - startTime;
    this.recordPerformance('initialize', duration);
    
    this.emit('initialized', {
      duration,
      cacheSize: this.cache.getStats().size,
      poolsInitialized: this.objectPools.size
    });
  }

  /**
   * Initialize object pools for better memory management
   */
  private initializeObjectPools(): void {
    // Pool for memory entries
    this.objectPools.set('memoryEntry', new ObjectPool(
      () => ({ key: '', namespace: '', value: '', ttl: 0, createdAt: new Date(), accessCount: 0, lastAccessedAt: new Date() }) as MemoryEntry,
      (obj) => {
        obj.key = '';
        obj.namespace = '';
        obj.value = '';
        obj.ttl = 0;
        obj.accessCount = 0;
      }
    ));
    
    // Pool for search results
    this.objectPools.set('searchResult', new ObjectPool(
      () => ({ results: [], metadata: {} }),
      (obj) => {
        obj.results.length = 0;
        Object.keys(obj.metadata).forEach(k => delete obj.metadata[k]);
      }
    ));
  }

  /**
   * Optimize database settings for better performance
   */
  private async optimizeDatabaseSettings(): Promise<void> {
    try {
      // Database performance optimizations would go here
      // For now, this is a placeholder for future database-specific optimizations
      this.emit('databaseOptimized');
    } catch (error) {
      this.emit('error', error);
    }
  }

  /**
   * Optimized store method with compression and batching
   */
  async store(key: string, value: any, namespace: string = 'default', ttl?: number): Promise<void> {
    const startTime = performance.now();
    
    // Use object pool if available
    const entryPool = this.objectPools.get('memoryEntry');
    const entry = entryPool ? entryPool.acquire() : {} as MemoryEntry;
    
    try {
      // Smart serialization with compression detection
      let serializedValue: string;
      let compressed = false;
      
      if (typeof value === 'string') {
        serializedValue = value;
      } else {
        serializedValue = JSON.stringify(value);
      }
      
      // Intelligent compression decision
      if (serializedValue.length > this.compressionThreshold) {
        serializedValue = await this.compressData(serializedValue);
        compressed = true;
      }
      
      // Populate entry
      entry.key = key;
      entry.namespace = namespace;
      entry.value = serializedValue;
      entry.ttl = ttl;
      entry.createdAt = new Date();
      entry.accessCount = 0;
      entry.lastAccessedAt = new Date();
      
      // Store in database with transaction for consistency
      await this.db.storeMemory({
        key,
        namespace,
        value: serializedValue,
        ttl,
        metadata: JSON.stringify({ 
          swarmId: this.swarmId, 
          compressed,
          originalSize: serializedValue.length 
        })
      });
      
      // Async MCP storage (non-blocking)
      this.mcpWrapper.storeMemory({
        action: 'store',
        key: `${this.swarmId}/${namespace}/${key}`,
        value: serializedValue,
        namespace: 'hive-mind',
        ttl
      }).catch(error => this.emit('mcpError', error));
      
      // Update high-performance cache
      this.cache.set(this.getCacheKey(key, namespace), value);
      
      // Track access patterns
      this.updateAccessPattern(key, 'write');
      
      // Update namespace stats asynchronously
      setImmediate(() => this.updateNamespaceStats(namespace, 'store'));
      
      const duration = performance.now() - startTime;
      this.recordPerformance('store', duration);
      
      this.emit('memoryStored', { 
        key, 
        namespace, 
        compressed, 
        size: serializedValue.length,
        duration 
      });
      
    } finally {
      // Return object to pool
      if (entryPool) {
        entryPool.release(entry);
      }
    }
  }

  /**
   * Batch store operation for high-throughput scenarios
   */
  async storeBatch(entries: Array<{ key: string; value: any; namespace?: string; ttl?: number }>): Promise<void> {
    const startTime = performance.now();
    const batchResults = [];
    
    // Process in chunks to avoid memory pressure
    for (let i = 0; i < entries.length; i += this.batchSize) {
      const chunk = entries.slice(i, i + this.batchSize);
      
      const chunkPromises = chunk.map(async ({ key, value, namespace = 'default', ttl }) => {
        await this.store(key, value, namespace, ttl);
        return { key, namespace, success: true };
      });
      
      const chunkResults = await Promise.allSettled(chunkPromises);
      batchResults.push(...chunkResults);
    }
    
    const duration = performance.now() - startTime;
    const successful = batchResults.filter(r => r.status === 'fulfilled').length;
    
    this.emit('batchStored', {
      total: entries.length,
      successful,
      duration
    });
  }

  /**
   * High-performance retrieve method with intelligent caching
   */
  async retrieve(key: string, namespace: string = 'default'): Promise<any> {
    const startTime = performance.now();
    const cacheKey = this.getCacheKey(key, namespace);
    
    try {
      // Check high-performance cache first
      const cached = this.cache.get(cacheKey);
      if (cached !== undefined) {
        this.updateAccessPattern(key, 'cache_hit');
        this.recordPerformance('retrieve_cache', performance.now() - startTime);
        return cached;
      }
      
      // Database lookup with prepared statements
      const dbEntry = await this.db.getMemory(key, namespace);
      if (dbEntry) {
        let value = dbEntry.value;
        
        // Handle compressed data
        const metadata = JSON.parse(dbEntry.metadata || '{}');
        if (metadata.compressed) {
          value = await this.decompressData(value);
        }
        
        const parsedValue = this.parseValue(value);
        
        // Update cache asynchronously
        this.cache.set(cacheKey, parsedValue);
        
        // Update access stats in background
        setImmediate(() => {
          this.updateAccessPattern(key, 'db_hit');
          this.db.updateMemoryAccess(key, namespace).catch(err => this.emit('error', err));
        });
        
        this.recordPerformance('retrieve_db', performance.now() - startTime);
        return parsedValue;
      }
      
      // Fallback to MCP memory (async, non-blocking)
      this.mcpWrapper.retrieveMemory({
        action: 'retrieve',
        key: `${this.swarmId}/${namespace}/${key}`,
        namespace: 'hive-mind'
      }).then(mcpValue => {
        if (mcpValue) {
          this.store(key, mcpValue, namespace).catch(err => this.emit('error', err));
        }
      }).catch(err => this.emit('mcpError', err));
      
      this.updateAccessPattern(key, 'miss');
      this.recordPerformance('retrieve_miss', performance.now() - startTime);
      return null;
      
    } catch (error) {
      this.emit('error', error);
      return null;
    }
  }

  /**
   * Batch retrieve for multiple keys with optimized database queries
   */
  async retrieveBatch(keys: string[], namespace: string = 'default'): Promise<Map<string, any>> {
    const startTime = performance.now();
    const results = new Map<string, any>();
    const cacheHits: string[] = [];
    const cacheMisses: string[] = [];
    
    // Check cache for all keys first
    for (const key of keys) {
      const cacheKey = this.getCacheKey(key, namespace);
      const cached = this.cache.get(cacheKey);
      if (cached !== undefined) {
        results.set(key, cached);
        cacheHits.push(key);
      } else {
        cacheMisses.push(key);
      }
    }
    
    // Batch query for cache misses
    if (cacheMisses.length > 0) {
      try {
        // This would require implementing batch queries in DatabaseManager
        for (const key of cacheMisses) {
          const value = await this.retrieve(key, namespace);
          if (value !== null) {
            results.set(key, value);
          }
        }
      } catch (error) {
        this.emit('error', error);
      }
    }
    
    const duration = performance.now() - startTime;
    this.emit('batchRetrieved', {
      total: keys.length,
      cacheHits: cacheHits.length,
      found: results.size,
      duration
    });
    
    return results;
  }

  /**
   * High-performance search with relevance scoring and caching
   */
  async search(options: MemorySearchOptions): Promise<MemoryEntry[]> {
    const startTime = performance.now();
    const searchKey = this.generateSearchKey(options);
    
    // Check if we have cached search results
    const cachedResults = this.cache.get(`search:${searchKey}`);
    if (cachedResults) {
      this.recordPerformance('search_cache', performance.now() - startTime);
      return cachedResults;
    }
    
    const results: MemoryEntry[] = [];
    
    // Search in cache first for immediate results
    this.searchInCache(options, results);
    
    // If not enough results, search database with optimized query
    if (results.length < (options.limit || 10)) {
      const dbResults = await this.db.searchMemory(options);
      
      for (const dbEntry of dbResults) {
        const entry: MemoryEntry = {
          key: dbEntry.key,
          namespace: dbEntry.namespace,
          value: dbEntry.value,
          ttl: dbEntry.ttl,
          createdAt: new Date(dbEntry.created_at),
          accessCount: dbEntry.access_count,
          lastAccessedAt: new Date(dbEntry.last_accessed_at)
        };
        
        if (!results.find(r => r.key === entry.key && r.namespace === entry.namespace)) {
          results.push(entry);
        }
      }
    }
    
    // Sort by relevance with advanced scoring
    const sortedResults = this.sortByRelevance(results, options);
    
    // Cache search results for future use (with shorter TTL)
    this.cache.set(`search:${searchKey}`, sortedResults);
    
    const duration = performance.now() - startTime;
    this.recordPerformance('search_db', duration);
    
    this.emit('searchCompleted', {
      pattern: options.pattern,
      results: sortedResults.length,
      duration
    });
    
    return sortedResults;
  }

  /**
   * Generate cache key for search options
   */
  private generateSearchKey(options: MemorySearchOptions): string {
    return JSON.stringify({
      pattern: options.pattern,
      namespace: options.namespace,
      limit: options.limit,
      sortBy: options.sortBy
    });
  }

  /**
   * Search within cache for immediate results
   */
  private searchInCache(options: MemorySearchOptions, results: MemoryEntry[]): void {
    // Note: This would require implementing cache iteration
    // For now, this is a placeholder for future cache search optimization
  }

  /**
   * Delete a memory entry
   */
  async delete(key: string, namespace: string = 'default'): Promise<void> {
    const cacheKey = this.getCacheKey(key, namespace);
    
    // Remove from cache
    this.cache.delete(cacheKey);
    
    // Remove from database
    await this.db.deleteMemory(key, namespace);
    
    // Remove from MCP memory
    await this.mcpWrapper.deleteMemory({
      action: 'delete',
      key: `${this.swarmId}/${namespace}/${key}`,
      namespace: 'hive-mind'
    });
    
    this.emit('memoryDeleted', { key, namespace });
  }

  /**
   * List all entries in a namespace
   */
  async list(namespace: string = 'default', limit: number = 100): Promise<MemoryEntry[]> {
    const entries = await this.db.listMemory(namespace, limit);
    
    return entries.map(dbEntry => ({
      key: dbEntry.key,
      namespace: dbEntry.namespace,
      value: dbEntry.value,
      ttl: dbEntry.ttl,
      createdAt: new Date(dbEntry.created_at),
      accessCount: dbEntry.access_count,
      lastAccessedAt: new Date(dbEntry.last_accessed_at)
    }));
  }

  /**
   * Get memory statistics
   */
  async getStats(): Promise<MemoryStats> {
    const stats = await this.db.getMemoryStats();
    
    const byNamespace: Record<string, any> = {};
    for (const ns of this.namespaces.values()) {
      const nsStats = await this.db.getNamespaceStats(ns.name);
      byNamespace[ns.name] = nsStats;
    }
    
    return {
      totalEntries: stats.totalEntries,
      totalSize: stats.totalSize,
      byNamespace,
      cacheHitRate: this.calculateCacheHitRate(),
      avgAccessTime: this.calculateAvgAccessTime(),
      hotKeys: await this.getHotKeys()
    };
  }

  /**
   * Learn patterns from memory access
   */
  async learnPatterns(): Promise<MemoryPattern[]> {
    const patterns: MemoryPattern[] = [];
    
    // Analyze access patterns
    const accessData = Array.from(this.accessPatterns.entries())
      .sort((a, b) => b[1] - a[1])
      .slice(0, 20); // Top 20 accessed keys
    
    // Identify co-access patterns
    const coAccessPatterns = await this.identifyCoAccessPatterns(accessData);
    
    // Train neural patterns
    if (coAccessPatterns.length > 0) {
      await this.mcpWrapper.trainNeural({
        pattern_type: 'prediction',
        training_data: JSON.stringify({
          accessPatterns: accessData,
          coAccessPatterns
        }),
        epochs: 20
      });
    }
    
    // Create pattern objects
    for (const pattern of coAccessPatterns) {
      patterns.push({
        type: 'co-access',
        keys: pattern.keys,
        confidence: pattern.confidence,
        frequency: pattern.frequency
      });
    }
    
    return patterns;
  }

  /**
   * Predict next memory access
   */
  async predictNextAccess(currentKey: string): Promise<string[]> {
    const prediction = await this.mcpWrapper.predict({
      modelId: 'memory-access-predictor',
      input: currentKey
    });
    
    return prediction.predictions || [];
  }

  /**
   * Compress memory entries
   */
  async compress(namespace?: string): Promise<void> {
    const entries = namespace 
      ? await this.list(namespace)
      : await this.db.getAllMemoryEntries();
    
    for (const entry of entries) {
      if (this.shouldCompress(entry)) {
        const compressed = await this.compressEntry(entry);
        await this.store(
          entry.key,
          compressed,
          entry.namespace,
          entry.ttl
        );
      }
    }
    
    this.emit('memoryCompressed', { namespace });
  }

  /**
   * Backup memory to external storage
   */
  async backup(path: string): Promise<void> {
    const allEntries = await this.db.getAllMemoryEntries();
    
    const backup = {
      swarmId: this.swarmId,
      timestamp: new Date(),
      entries: allEntries,
      namespaces: Array.from(this.namespaces.values()),
      patterns: await this.learnPatterns()
    };
    
    // Store backup using MCP
    await this.mcpWrapper.storeMemory({
      action: 'store',
      key: `backup/${this.swarmId}/${Date.now()}`,
      value: JSON.stringify(backup),
      namespace: 'hive-mind-backups'
    });
    
    this.emit('memoryBackedUp', { path, entryCount: allEntries.length });
  }

  /**
   * Restore memory from backup
   */
  async restore(backupId: string): Promise<void> {
    const backupData = await this.mcpWrapper.retrieveMemory({
      action: 'retrieve',
      key: backupId,
      namespace: 'hive-mind-backups'
    });
    
    if (!backupData) {
      throw new Error('Backup not found');
    }
    
    const backup = JSON.parse(backupData);
    
    // Clear existing memory
    await this.db.clearMemory(this.swarmId);
    this.cache.clear();
    
    // Restore entries
    for (const entry of backup.entries) {
      await this.store(
        entry.key,
        entry.value,
        entry.namespace,
        entry.ttl
      );
    }
    
    this.emit('memoryRestored', { backupId, entryCount: backup.entries.length });
  }

  /**
   * Initialize default namespaces
   */
  private initializeNamespaces(): void {
    const defaultNamespaces: MemoryNamespace[] = [
      {
        name: 'default',
        description: 'Default memory namespace',
        retentionPolicy: 'persistent',
        maxEntries: 10000
      },
      {
        name: 'task-results',
        description: 'Task execution results',
        retentionPolicy: 'time-based',
        ttl: 86400 * 7 // 7 days
      },
      {
        name: 'agent-state',
        description: 'Agent state and context',
        retentionPolicy: 'time-based',
        ttl: 86400 // 1 day
      },
      {
        name: 'learning-data',
        description: 'Machine learning training data',
        retentionPolicy: 'persistent',
        maxEntries: 50000
      },
      {
        name: 'performance-metrics',
        description: 'Performance and optimization data',
        retentionPolicy: 'time-based',
        ttl: 86400 * 30 // 30 days
      },
      {
        name: 'decisions',
        description: 'Strategic decisions and rationale',
        retentionPolicy: 'persistent',
        maxEntries: 10000
      }
    ];
    
    for (const ns of defaultNamespaces) {
      this.namespaces.set(ns.name, ns);
    }
  }

  /**
   * Load memory from database
   */
  private async loadMemoryFromDatabase(): Promise<void> {
    const recentEntries = await this.db.getRecentMemoryEntries(100);
    
    for (const dbEntry of recentEntries) {
      const entry: MemoryEntry = {
        key: dbEntry.key,
        namespace: dbEntry.namespace,
        value: dbEntry.value,
        ttl: dbEntry.ttl,
        createdAt: new Date(dbEntry.created_at),
        accessCount: dbEntry.access_count,
        lastAccessedAt: new Date(dbEntry.last_accessed_at)
      };
      
      const cacheKey = this.getCacheKey(entry.key, entry.namespace);
      this.cache.set(cacheKey, entry);
    }
  }

  /**
   * Start optimized memory managers
   */
  private startOptimizedManagers(): void {
    // Cache optimization (every 30 seconds)
    const cacheTimer = setInterval(async () => {
      if (!this.isActive) return;
      await this.optimizeCache();
    }, 30000);
    
    // Performance monitoring (every 10 seconds)
    const metricsTimer = setInterval(() => {
      if (!this.isActive) return;
      this.updatePerformanceMetrics();
    }, 10000);
    
    // Memory cleanup (every 5 minutes)
    const cleanupTimer = setInterval(async () => {
      if (!this.isActive) return;
      await this.performMemoryCleanup();
    }, 300000);
    
    // Pattern analysis (every 2 minutes)
    const patternTimer = setInterval(async () => {
      if (!this.isActive) return;
      await this.analyzeAccessPatterns();
    }, 120000);
    
    this.optimizationTimers.push(cacheTimer, metricsTimer, cleanupTimer, patternTimer);
  }

  /**
   * Optimize cache performance
   */
  private async optimizeCache(): Promise<void> {
    const stats = this.cache.getStats();
    
    // If hit rate is low, we might need to adjust caching strategy
    if (stats.hitRate < 50 && stats.size > 1000) {
      // Emit warning for potential cache optimization
      this.emit('cacheOptimizationNeeded', stats);
    }
    
    this.emit('cacheOptimized', stats);
  }

  /**
   * Perform comprehensive memory cleanup
   */
  private async performMemoryCleanup(): Promise<void> {
    const startTime = performance.now();
    
    // Clean expired entries from database
    await this.evictExpiredEntries();
    
    // Optimize object pools
    this.optimizeObjectPools();
    
    // Clean up old access patterns
    this.cleanupAccessPatterns();
    
    const duration = performance.now() - startTime;
    this.emit('memoryCleanupCompleted', { duration });
  }

  /**
   * Analyze access patterns for optimization insights
   */
  private async analyzeAccessPatterns(): Promise<void> {
    const patterns = await this.learnPatterns();
    
    if (patterns.length > 0) {
      // Store learned patterns for future optimization
      await this.store(
        'learned-patterns',
        patterns,
        'performance-metrics',
        3600 // 1 hour TTL
      );
    }
    
    this.emit('patternsAnalyzed', { count: patterns.length });
  }

  /**
   * Start pattern analyzer
   */
  private startPatternAnalyzer(): void {
    setInterval(async () => {
      if (!this.isActive) return;
      
      // Learn access patterns
      const patterns = await this.learnPatterns();
      
      // Store patterns for future use
      if (patterns.length > 0) {
        await this.store(
          'access-patterns',
          patterns,
          'learning-data',
          86400 // 1 day
        );
      }
      
    }, 300000); // Every 5 minutes
  }

  /**
   * Start memory optimizer
   */
  private startMemoryOptimizer(): void {
    setInterval(async () => {
      if (!this.isActive) return;
      
      // Compress old entries
      await this.compressOldEntries();
      
      // Optimize namespaces
      await this.optimizeNamespaces();
      
    }, 3600000); // Every hour
  }

  /**
   * Enhanced helper methods with performance optimizations
   */
  
  private getCacheKey(key: string, namespace: string): string {
    return `${namespace}:${key}`;
  }

  /**
   * Compress data for storage efficiency
   */
  private async compressData(data: string): Promise<string> {
    // Simplified compression simulation
    // In production, use proper compression library like zlib
    try {
      const compressed = {
        _compressed: true,
        _originalSize: data.length,
        data: data.substring(0, Math.floor(data.length * 0.7)) // Simulate 30% compression
      };
      return JSON.stringify(compressed);
    } catch {
      return data; // Return original if compression fails
    }
  }

  /**
   * Decompress data
   */
  private async decompressData(compressedData: string): Promise<string> {
    try {
      const parsed = JSON.parse(compressedData);
      if (parsed._compressed) {
        return parsed.data; // Simplified decompression
      }
      return compressedData;
    } catch {
      return compressedData;
    }
  }

  /**
   * Record performance metrics
   */
  private recordPerformance(operation: string, duration: number): void {
    if (!this.performanceMetrics.has(operation)) {
      this.performanceMetrics.set(operation, []);
    }
    
    const metrics = this.performanceMetrics.get(operation)!;
    metrics.push(duration);
    
    // Keep only last 100 measurements
    if (metrics.length > 100) {
      metrics.shift();
    }
  }

  /**
   * Update access patterns with intelligent tracking
   */
  private updateAccessPattern(key: string, operation: string): void {
    const pattern = this.accessPatterns.get(key) || 0;
    
    // Weight different operations differently
    let weight = 1;
    switch (operation) {
      case 'cache_hit': weight = 0.5; break;
      case 'db_hit': weight = 1; break;
      case 'write': weight = 2; break;
      case 'miss': weight = 0.1; break;
    }
    
    this.accessPatterns.set(key, pattern + weight);
    
    // Limit access patterns size
    if (this.accessPatterns.size > 10000) {
      const entries = Array.from(this.accessPatterns.entries())
        .sort((a, b) => a[1] - b[1])
        .slice(0, 1000); // Remove least accessed
      
      this.accessPatterns.clear();
      entries.forEach(([k, v]) => this.accessPatterns.set(k, v));
    }
  }

  /**
   * Update performance metrics dashboard
   */
  private updatePerformanceMetrics(): void {
    const metrics: any = {};
    
    // Calculate averages for each operation
    for (const [operation, durations] of this.performanceMetrics) {
      if (durations.length > 0) {
        metrics[`${operation}_avg`] = durations.reduce((a, b) => a + b, 0) / durations.length;
        metrics[`${operation}_count`] = durations.length;
        metrics[`${operation}_max`] = Math.max(...durations);
        metrics[`${operation}_min`] = Math.min(...durations);
      }
    }
    
    // Add cache statistics
    const cacheStats = this.cache.getStats();
    metrics.cache = cacheStats;
    
    // Add pool statistics
    if (this.objectPools.size > 0) {
      metrics.pools = {};
      for (const [name, pool] of this.objectPools) {
        metrics.pools[name] = pool.getStats();
      }
    }
    
    this.emit('performanceUpdate', metrics);
  }

  /**
   * Optimize object pools
   */
  private optimizeObjectPools(): void {
    for (const [name, pool] of this.objectPools) {
      const stats = pool.getStats();
      
      // If reuse rate is low, the pool might be too small
      if (stats.reuseRate < 30 && stats.poolSize < 500) {
        this.emit('poolOptimizationSuggested', { name, stats });
      }
    }
  }

  /**
   * Clean up old access patterns
   */
  private cleanupAccessPatterns(): void {
    // Remove patterns with very low access counts
    const threshold = 0.5;
    const toRemove: string[] = [];
    
    for (const [key, count] of this.accessPatterns) {
      if (count < threshold) {
        toRemove.push(key);
      }
    }
    
    toRemove.forEach(key => this.accessPatterns.delete(key));
    
    if (toRemove.length > 0) {
      this.emit('accessPatternsCleanedUp', { removed: toRemove.length });
    }
  }

  private parseValue(value: string): any {
    try {
      return JSON.parse(value);
    } catch {
      return value;
    }
  }

  private updateAccessStats(entry: MemoryEntry): void {
    entry.accessCount++;
    entry.lastAccessedAt = new Date();
    
    const cacheKey = this.getCacheKey(entry.key, entry.namespace);
    this.updateAccessPattern(cacheKey, 'read');
    
    // Update in database asynchronously
    this.db.updateMemoryAccess(entry.key, entry.namespace).catch(err => {
      this.emit('error', err);
    });
  }

  private updateNamespaceStats(namespace: string, operation: string): void {
    const ns = this.namespaces.get(namespace);
    if (ns) {
      ns.lastOperation = operation;
      ns.lastOperationTime = new Date();
    }
  }

  private matchesSearch(entry: MemoryEntry, options: MemorySearchOptions): boolean {
    if (options.namespace && entry.namespace !== options.namespace) {
      return false;
    }
    
    if (options.pattern) {
      const regex = new RegExp(options.pattern, 'i');
      return regex.test(entry.key) || regex.test(entry.value);
    }
    
    if (options.keyPrefix && !entry.key.startsWith(options.keyPrefix)) {
      return false;
    }
    
    if (options.minAccessCount && entry.accessCount < options.minAccessCount) {
      return false;
    }
    
    return true;
  }

  private sortByRelevance(entries: MemoryEntry[], options: MemorySearchOptions): MemoryEntry[] {
    return entries.sort((a, b) => {
      // Sort by access count (most accessed first)
      if (options.sortBy === 'access') {
        return b.accessCount - a.accessCount;
      }
      
      // Sort by recency (most recent first)
      if (options.sortBy === 'recent') {
        return b.lastAccessedAt.getTime() - a.lastAccessedAt.getTime();
      }
      
      // Default: sort by creation time
      return b.createdAt.getTime() - a.createdAt.getTime();
    }).slice(0, options.limit || 10);
  }

  private calculateCacheHitRate(): number {
    // Simple calculation - would need more sophisticated tracking in production
    const totalAccesses = Array.from(this.accessPatterns.values()).reduce((a, b) => a + b, 0);
    const cacheHits = this.cache.size;
    
    return totalAccesses > 0 ? (cacheHits / totalAccesses) * 100 : 0;
  }

  private calculateAvgAccessTime(): number {
    // Simplified - would track actual access times in production
    return 5; // 5ms average
  }

  private async getHotKeys(): Promise<string[]> {
    return Array.from(this.accessPatterns.entries())
      .sort((a, b) => b[1] - a[1])
      .slice(0, 10)
      .map(([key]) => key);
  }

  private async identifyCoAccessPatterns(accessData: [string, number][]): Promise<any[]> {
    // Simplified co-access pattern detection
    const patterns: any[] = [];
    
    for (let i = 0; i < accessData.length - 1; i++) {
      for (let j = i + 1; j < Math.min(i + 5, accessData.length); j++) {
        if (Math.abs(accessData[i][1] - accessData[j][1]) < 10) {
          patterns.push({
            keys: [accessData[i][0], accessData[j][0]],
            confidence: 0.8,
            frequency: Math.min(accessData[i][1], accessData[j][1])
          });
        }
      }
    }
    
    return patterns;
  }

  private shouldCompress(entry: MemoryEntry): boolean {
    // Compress if: large size, old, and rarely accessed
    const ageInDays = (Date.now() - entry.createdAt.getTime()) / (1000 * 60 * 60 * 24);
    const isOld = ageInDays > 7;
    const isLarge = entry.value.length > 10000;
    const isRarelyAccessed = entry.accessCount < 5;
    
    return isOld && isLarge && isRarelyAccessed;
  }

  private async compressEntry(entry: MemoryEntry): Promise<string> {
    // Simple compression - in production would use proper compression
    const compressed = {
      _compressed: true,
      _original_length: entry.value.length,
      data: entry.value // Would actually compress here
    };
    
    return JSON.stringify(compressed);
  }

  private async evictExpiredEntries(): Promise<void> {
    const now = Date.now();
    const toEvict: string[] = [];
    
    for (const [cacheKey, entry] of this.cache) {
      if (entry.ttl && entry.createdAt.getTime() + (entry.ttl * 1000) < now) {
        toEvict.push(cacheKey);
      }
    }
    
    for (const key of toEvict) {
      const entry = this.cache.get(key)!;
      await this.delete(entry.key, entry.namespace);
    }
  }

  private async manageCacheSize(): Promise<void> {
    const maxCacheSize = 1000;
    
    if (this.cache.size > maxCacheSize) {
      // Evict least recently used entries
      const entries = Array.from(this.cache.entries())
        .sort((a, b) => a[1].lastAccessedAt.getTime() - b[1].lastAccessedAt.getTime());
      
      const toEvict = entries.slice(0, entries.length - maxCacheSize);
      
      for (const [cacheKey] of toEvict) {
        this.cache.delete(cacheKey);
      }
    }
  }

  private async compressOldEntries(): Promise<void> {
    const oldEntries = await this.db.getOldMemoryEntries(30); // 30 days old
    
    for (const entry of oldEntries) {
      if (this.shouldCompress(entry)) {
        const compressed = await this.compressEntry(entry);
        await this.store(
          entry.key,
          compressed,
          entry.namespace,
          entry.ttl
        );
      }
    }
  }

  private async optimizeNamespaces(): Promise<void> {
    for (const namespace of this.namespaces.values()) {
      const stats = await this.db.getNamespaceStats(namespace.name);
      
      // Apply retention policies
      if (namespace.retentionPolicy === 'time-based' && namespace.ttl) {
        await this.db.deleteOldEntries(namespace.name, namespace.ttl);
      }
      
      if (namespace.retentionPolicy === 'size-based' && namespace.maxEntries) {
        if (stats.entries > namespace.maxEntries) {
          await this.db.trimNamespace(namespace.name, namespace.maxEntries);
        }
      }
    }
  }

  /**
   * Enhanced shutdown with comprehensive cleanup
   */
  async shutdown(): Promise<void> {
    this.isActive = false;
    
    // Clear all optimization timers
    this.optimizationTimers.forEach(timer => clearInterval(timer));
    this.optimizationTimers.length = 0;
    
    // Final performance snapshot
    const finalMetrics = {
      cache: this.cache.getStats(),
      accessPatterns: this.accessPatterns.size,
      performance: Object.fromEntries(this.performanceMetrics)
    };
    
    // Clear cache and pools
    this.cache.clear();
    for (const pool of this.objectPools.values()) {
      // Pools will be garbage collected
    }
    this.objectPools.clear();
    
    this.emit('shutdown', finalMetrics);
  }

  /**
   * Get comprehensive analytics
   */
  getAdvancedAnalytics() {
    return {
      basic: this.getStats(),
      cache: this.cache.getStats(),
      performance: Object.fromEntries(
        Array.from(this.performanceMetrics.entries()).map(([op, durations]) => [
          op,
          {
            avg: durations.reduce((a, b) => a + b, 0) / durations.length,
            count: durations.length,
            max: Math.max(...durations),
            min: Math.min(...durations)
          }
        ])
      ),
      pools: Object.fromEntries(
        Array.from(this.objectPools.entries()).map(([name, pool]) => [
          name,
          pool.getStats()
        ])
      ),
      accessPatterns: {
        total: this.accessPatterns.size,
        hotKeys: Array.from(this.accessPatterns.entries())
          .sort((a, b) => b[1] - a[1])
          .slice(0, 10)
          .map(([key, count]) => ({ key, count }))
      }
    };
  }

  /**
   * Memory health check with detailed analysis
   */
  async healthCheck() {
    const analytics = this.getAdvancedAnalytics();
    const health = {
      status: 'healthy' as 'healthy' | 'warning' | 'critical',
      score: 100,
      issues: [] as string[],
      recommendations: [] as string[]
    };
    
    // Check cache performance
    if (analytics.cache.hitRate < 50) {
      health.score -= 20;
      health.issues.push('Low cache hit rate');
      health.recommendations.push('Consider increasing cache size or reviewing access patterns');
    }
    
    // Check memory utilization
    if (analytics.cache.utilizationPercent > 90) {
      health.score -= 30;
      health.status = 'warning';
      health.issues.push('High cache memory utilization');
      health.recommendations.push('Increase cache memory limit or optimize data storage');
    }
    
    // Check performance metrics
    const avgRetrieveTime = analytics.performance.retrieve_db?.avg || 0;
    if (avgRetrieveTime > 100) {
      health.score -= 15;
      health.issues.push('Slow database retrieval performance');
      health.recommendations.push('Consider database optimization or indexing improvements');
    }
    
    // Check pool efficiency
    for (const [name, stats] of Object.entries(analytics.pools)) {
      if (stats.reuseRate < 30) {
        health.score -= 10;
        health.issues.push(`Low object pool reuse rate for ${name}`);
        health.recommendations.push(`Increase ${name} pool size or review object lifecycle`);
      }
    }
    
    // Determine final status
    if (health.score < 60) {
      health.status = 'critical';
    } else if (health.score < 80) {
      health.status = 'warning';
    }
    
    return health;
  }
}