import { getErrorMessage } from '../utils/error-handler.js';
/**
 * Distributed Memory System with Cross-Agent Sharing
 */

import { EventEmitter } from 'node:events';
import * as fs from 'node:fs/promises';
import * as path from 'node:path';
import * as crypto from 'node:crypto';
import { Logger } from '../core/logger.js';
import { generateId } from '../utils/helpers.js';
import {
  MemoryEntry, MemoryPartition, SwarmMemory, AccessLevel, ConsistencyLevel,
  MemoryType, MemoryPermissions, AgentId, SwarmEvent, SWARM_CONSTANTS
} from './types.js';

export interface MemoryQuery {
  namespace?: string;
  partition?: string;
  key?: string;
  tags?: string[];
  type?: MemoryType;
  owner?: AgentId;
  accessLevel?: AccessLevel;
  createdAfter?: Date;
  createdBefore?: Date;
  expiresAfter?: Date;
  limit?: number;
  offset?: number;
  sortBy?: 'createdAt' | 'updatedAt' | 'key' | 'relevance';
  sortOrder?: 'asc' | 'desc';
}

export interface MemorySearchOptions {
  query: string;
  searchFields?: string[];
  fuzzyMatch?: boolean;
  maxResults?: number;
  threshold?: number;
  includeContent?: boolean;
}

export interface MemoryStatistics {
  totalEntries: number;
  totalSize: number;
  partitionCount: number;
  entriesByType: Record<MemoryType, number>;
  entriesByAccess: Record<AccessLevel, number>;
  averageSize: number;
  oldestEntry: Date;
  newestEntry: Date;
  expiringEntries: number;
}

export interface MemoryBackup {
  timestamp: Date;
  version: string;
  checksum: string;
  metadata: Record<string, any>;
  entries: MemoryEntry[];
  partitions: MemoryPartition[];
}

export interface MemoryConfig {
  namespace: string;
  persistencePath: string;
  maxMemorySize: number;
  maxEntrySize: number;
  defaultTtl: number;
  enableCompression: boolean;
  enableEncryption: boolean;
  encryptionKey?: string;
  consistencyLevel: ConsistencyLevel;
  syncInterval: number;
  backupInterval: number;
  maxBackups: number;
  enableDistribution: boolean;
  distributionNodes: string[];
  replicationFactor: number;
  enableCaching: boolean;
  cacheSize: number;
  cacheTtl: number;
}

export class SwarmMemoryManager extends EventEmitter {
  private logger: Logger;
  private config: MemoryConfig;
  private memory: SwarmMemory;
  private partitions: Map<string, MemoryPartition> = new Map();
  private entries: Map<string, MemoryEntry> = new Map();
  private index: MemoryIndex;
  private cache: MemoryCache;
  private replication: MemoryReplication;
  private persistence: MemoryPersistence;
  private encryption: MemoryEncryption;
  private isInitialized = false;
  
  // Background processes
  private syncTimer?: NodeJS.Timeout;
  private backupTimer?: NodeJS.Timeout;
  private cleanupTimer?: NodeJS.Timeout;

  constructor(config: Partial<MemoryConfig & { logging?: any }> = {}) {
    super();
    
    // Configure logger based on config or default to quiet mode
    const logLevel = config.logging?.level || 'error';
    const logFormat = config.logging?.format || 'text';
    const logDestination = config.logging?.destination || 'console';
    
    this.logger = new Logger(
      { level: logLevel, format: logFormat, destination: logDestination },
      { component: 'SwarmMemoryManager' }
    );
    this.config = this.mergeWithDefaults(config);
    
    // Initialize memory structure
    this.memory = {
      namespace: this.config.namespace,
      partitions: [],
      permissions: {
        read: 'swarm',
        write: 'team',
        delete: 'private',
        share: 'team'
      },
      persistent: true,
      backupEnabled: true,
      distributed: this.config.enableDistribution,
      consistency: this.config.consistencyLevel,
      cacheEnabled: this.config.enableCaching,
      compressionEnabled: this.config.enableCompression
    };

    // Initialize subsystems
    this.index = new MemoryIndex();
    this.cache = new MemoryCache(this.config.cacheSize, this.config.cacheTtl);
    this.replication = new MemoryReplication(this.config);
    this.persistence = new MemoryPersistence(this.config);
    this.encryption = new MemoryEncryption(this.config);
    
    this.setupEventHandlers();
  }

  async initialize(): Promise<void> {
    if (this.isInitialized) {
      return;
    }

    this.logger.info('Initializing swarm memory manager...');

    try {
      // Initialize subsystems
      await this.persistence.initialize();
      await this.encryption.initialize();
      await this.replication.initialize();
      await this.index.initialize();
      
      // Load existing data
      await this.loadMemoryState();
      
      // Create default partitions
      await this.createDefaultPartitions();
      
      // Start background processes
      this.startBackgroundProcesses();
      
      this.isInitialized = true;
      
      this.emit('memory:initialized', {
        namespace: this.config.namespace,
        entriesLoaded: this.entries.size,
        partitionsLoaded: this.partitions.size
      });
      
      this.logger.info('Swarm memory manager initialized', {
        namespace: this.config.namespace,
        entries: this.entries.size,
        partitions: this.partitions.size
      });

    } catch (error) {
      this.logger.error('Failed to initialize memory manager', { error });
      throw error;
    }
  }

  async shutdown(): Promise<void> {
    if (!this.isInitialized) {
      return;
    }

    this.logger.info('Shutting down swarm memory manager...');

    try {
      // Stop background processes
      this.stopBackgroundProcesses();
      
      // Save final state
      await this.saveMemoryState();
      
      // Shutdown subsystems
      await this.replication.shutdown();
      await this.persistence.shutdown();
      await this.encryption.shutdown();
      
      this.isInitialized = false;
      
      this.emit('memory:shutdown');
      this.logger.info('Swarm memory manager shut down');

    } catch (error) {
      this.logger.error('Error during memory manager shutdown', { error });
    }
  }

  // ===== MEMORY OPERATIONS =====

  async store(
    key: string,
    value: any,
    options: Partial<{
      partition: string;
      type: MemoryType;
      tags: string[];
      owner: AgentId;
      accessLevel: AccessLevel;
      ttl: number;
      metadata: Record<string, any>;
    }> = {}
  ): Promise<string> {
    this.ensureInitialized();

    const entryId = generateId('mem');
    const now = new Date();
    
    // Validate access permissions
    if (options.owner) {
      await this.validateAccess(options.owner, 'write', options.partition);
    }

    // Determine partition
    const partitionName = options.partition || 'default';
    const partition = await this.getOrCreatePartition(partitionName);

    // Create memory entry
    const entry: MemoryEntry = {
      id: entryId,
      key,
      value: await this.serializeValue(value),
      type: options.type || 'knowledge',
      tags: options.tags || [],
      owner: options.owner || { id: 'system', swarmId: '', type: 'coordinator', instance: 0 },
      accessLevel: options.accessLevel || 'team',
      createdAt: now,
      updatedAt: now,
      expiresAt: options.ttl ? new Date(now.getTime() + options.ttl) : undefined,
      version: 1,
      references: [],
      dependencies: []
    };

    // Validate entry size
    const entrySize = this.calculateEntrySize(entry);
    if (entrySize > this.config.maxEntrySize) {
      throw new Error(`Entry size ${entrySize} exceeds maximum ${this.config.maxEntrySize}`);
    }

    // Check memory limits
    await this.enforceMemoryLimits(entrySize);

    // Store entry
    this.entries.set(entryId, entry);
    partition.entries.push(entry);

    // Update index
    await this.index.addEntry(entry);

    // Update cache
    if (this.config.enableCaching) {
      this.cache.set(key, entry);
    }

    // Replicate if enabled
    if (this.config.enableDistribution) {
      await this.replication.replicate(entry);
    }

    // Emit event
    this.emit('memory:stored', {
      entryId,
      key,
      partition: partitionName,
      type: entry.type,
      size: entrySize
    });

    this.logger.debug('Stored memory entry', {
      entryId,
      key,
      partition: partitionName,
      type: entry.type,
      size: entrySize
    });

    return entryId;
  }

  async retrieve(
    key: string,
    options: Partial<{
      partition: string;
      requester: AgentId;
      includeMetadata: boolean;
    }> = {}
  ): Promise<any> {
    this.ensureInitialized();

    // Try cache first
    if (this.config.enableCaching) {
      const cached = this.cache.get(key);
      if (cached && !this.isExpired(cached)) {
        if (options.requester) {
          await this.validateAccess(options.requester, 'read', options.partition);
        }
        return options.includeMetadata ? cached : await this.deserializeValue(cached.value);
      }
    }

    // Find entry
    const entry = await this.findEntry(key, options.partition);
    if (!entry) {
      return null;
    }

    // Check expiration
    if (this.isExpired(entry)) {
      await this.deleteEntry(entry.id);
      return null;
    }

    // Validate access
    if (options.requester) {
      await this.validateAccess(options.requester, 'read', options.partition);
    }

    // Update cache
    if (this.config.enableCaching) {
      this.cache.set(key, entry);
    }

    // Emit event
    this.emit('memory:retrieved', {
      entryId: entry.id,
      key,
      requester: options.requester?.id
    });

    return options.includeMetadata ? entry : await this.deserializeValue(entry.value);
  }

  async update(
    key: string,
    value: any,
    options: Partial<{
      partition: string;
      updater: AgentId;
      metadata: Record<string, any>;
      incrementVersion: boolean;
    }> = {}
  ): Promise<boolean> {
    this.ensureInitialized();

    const entry = await this.findEntry(key, options.partition);
    if (!entry) {
      return false;
    }

    // Validate access
    if (options.updater) {
      await this.validateAccess(options.updater, 'write', options.partition);
    }

    // Create backup of old version
    if (options.incrementVersion !== false) {
      entry.previousVersions = entry.previousVersions || [];
      entry.previousVersions.push({ ...entry });
      
      // Limit version history
      if (entry.previousVersions.length > 10) {
        entry.previousVersions = entry.previousVersions.slice(-10);
      }
    }

    // Update entry
    entry.value = await this.serializeValue(value);
    entry.updatedAt = new Date();
    if (options.incrementVersion !== false) {
      entry.version++;
    }

    // Update index
    await this.index.updateEntry(entry);

    // Update cache
    if (this.config.enableCaching) {
      this.cache.set(key, entry);
    }

    // Replicate if enabled
    if (this.config.enableDistribution) {
      await this.replication.replicate(entry);
    }

    this.emit('memory:updated', {
      entryId: entry.id,
      key,
      version: entry.version,
      updater: options.updater?.id
    });

    return true;
  }

  async delete(
    key: string,
    options: Partial<{
      partition: string;
      deleter: AgentId;
      force: boolean;
    }> = {}
  ): Promise<boolean> {
    this.ensureInitialized();

    const entry = await this.findEntry(key, options.partition);
    if (!entry) {
      return false;
    }

    // Validate access
    if (options.deleter && !options.force) {
      await this.validateAccess(options.deleter, 'delete', options.partition);
    }

    return await this.deleteEntry(entry.id);
  }

  async query(query: MemoryQuery): Promise<MemoryEntry[]> {
    this.ensureInitialized();

    let results = Array.from(this.entries.values());

    // Apply filters
    if (query.partition) {
      const partition = this.partitions.get(query.partition);
      if (partition) {
        const entryIds = new Set(partition.entries.map(e => e.id));
        results = results.filter(e => entryIds.has(e.id));
      } else {
        return [];
      }
    }

    if (query.key) {
      results = results.filter(e => e.key === query.key);
    }

    if (query.type) {
      results = results.filter(e => e.type === query.type);
    }

    if (query.owner) {
      results = results.filter(e => e.owner.id === query.owner!.id);
    }

    if (query.accessLevel) {
      results = results.filter(e => e.accessLevel === query.accessLevel);
    }

    if (query.tags && query.tags.length > 0) {
      results = results.filter(e => 
        query.tags!.some(tag => e.tags.includes(tag))
      );
    }

    if (query.createdAfter) {
      results = results.filter(e => e.createdAt >= query.createdAfter!);
    }

    if (query.createdBefore) {
      results = results.filter(e => e.createdAt <= query.createdBefore!);
    }

    if (query.expiresAfter) {
      results = results.filter(e => 
        e.expiresAt && e.expiresAt >= query.expiresAfter!
      );
    }

    // Filter out expired entries
    results = results.filter(e => !this.isExpired(e));

    // Sort results
    if (query.sortBy) {
      results.sort((a, b) => {
        let compareValue = 0;
        
        switch (query.sortBy) {
          case 'createdAt':
            compareValue = a.createdAt.getTime() - b.createdAt.getTime();
            break;
          case 'updatedAt':
            compareValue = a.updatedAt.getTime() - b.updatedAt.getTime();
            break;
          case 'key':
            compareValue = a.key.localeCompare(b.key);
            break;
          default:
            compareValue = 0;
        }
        
        return query.sortOrder === 'desc' ? -compareValue : compareValue;
      });
    }

    // Apply pagination
    const offset = query.offset || 0;
    const limit = query.limit || results.length;
    results = results.slice(offset, offset + limit);

    return results;
  }

  async search(options: MemorySearchOptions): Promise<MemoryEntry[]> {
    this.ensureInitialized();
    return await this.index.search(options);
  }

  // ===== SHARING AND COLLABORATION =====

  async shareMemory(
    key: string,
    targetAgent: AgentId,
    options: Partial<{
      partition: string;
      sharer: AgentId;
      accessLevel: AccessLevel;
      expiresAt: Date;
    }> = {}
  ): Promise<string> {
    this.ensureInitialized();

    const entry = await this.findEntry(key, options.partition);
    if (!entry) {
      throw new Error(`Memory entry not found: ${key}`);
    }

    // Validate sharing permissions
    if (options.sharer) {
      await this.validateAccess(options.sharer, 'share', options.partition);
    }

    // Create shared copy
    const sharedEntryId = generateId('shared-mem');
    const sharedEntry: MemoryEntry = {
      ...entry,
      id: sharedEntryId,
      owner: targetAgent,
      accessLevel: options.accessLevel || entry.accessLevel,
      createdAt: new Date(),
      updatedAt: new Date(),
      expiresAt: options.expiresAt,
      references: [...entry.references, entry.id]
    };

    // Store shared entry
    this.entries.set(sharedEntryId, sharedEntry);
    await this.index.addEntry(sharedEntry);

    // Add to target agent's partition
    const targetPartition = await this.getOrCreatePartition(`agent_${targetAgent.id}`);
    targetPartition.entries.push(sharedEntry);

    this.emit('memory:shared', {
      originalId: entry.id,
      sharedId: sharedEntryId,
      key,
      sharer: options.sharer?.id,
      target: targetAgent.id
    });

    this.logger.info('Shared memory entry', {
      key,
      from: options.sharer?.id,
      to: targetAgent.id,
      sharedId: sharedEntryId
    });

    return sharedEntryId;
  }

  async broadcastMemory(
    key: string,
    targetAgents: AgentId[],
    options: Partial<{
      partition: string;
      broadcaster: AgentId;
      accessLevel: AccessLevel;
    }> = {}
  ): Promise<string[]> {
    this.ensureInitialized();

    const sharedIds: string[] = [];

    for (const targetAgent of targetAgents) {
      try {
        const sharedId = await this.shareMemory(key, targetAgent, {
          ...options,
          sharer: options.broadcaster
        });
        sharedIds.push(sharedId);
      } catch (error) {
        this.logger.warn('Failed to share memory with agent', {
          key,
          targetAgent: targetAgent.id,
          error: (error instanceof Error ? error.message : String(error))
        });
      }
    }

    this.emit('memory:broadcasted', {
      key,
      broadcaster: options.broadcaster?.id,
      targets: targetAgents.map(a => a.id),
      sharedCount: sharedIds.length
    });

    return sharedIds;
  }

  async synchronizeWith(
    targetNode: string,
    options: Partial<{
      partition: string;
      direction: 'pull' | 'push' | 'bidirectional';
      filter: MemoryQuery;
    }> = {}
  ): Promise<void> {
    this.ensureInitialized();

    if (!this.config.enableDistribution) {
      throw new Error('Distribution not enabled');
    }

    await this.replication.synchronizeWith(targetNode, options);

    this.emit('memory:synchronized', {
      targetNode,
      direction: options.direction || 'bidirectional',
      partition: options.partition
    });
  }

  // ===== PARTITION MANAGEMENT =====

  async createPartition(
    name: string,
    options: Partial<{
      type: MemoryType;
      maxSize: number;
      ttl: number;
      readOnly: boolean;
      shared: boolean;
      indexed: boolean;
      compressed: boolean;
    }> = {},
    skipInitCheck: boolean = false
  ): Promise<string> {
    if (!skipInitCheck) {
      this.ensureInitialized();
    }

    if (this.partitions.has(name)) {
      throw new Error(`Partition already exists: ${name}`);
    }

    const partition: MemoryPartition = {
      id: generateId('partition'),
      name,
      type: options.type || 'knowledge',
      entries: [],
      maxSize: options.maxSize || this.config.maxMemorySize,
      ttl: options.ttl,
      readOnly: options.readOnly || false,
      shared: options.shared || true,
      indexed: options.indexed !== false,
      compressed: options.compressed || this.config.enableCompression
    };

    this.partitions.set(name, partition);
    this.memory.partitions.push(partition);

    this.emit('memory:partition-created', {
      partitionId: partition.id,
      name,
      type: partition.type
    });

    this.logger.info('Created memory partition', {
      name,
      type: partition.type,
      maxSize: partition.maxSize
    });

    return partition.id;
  }

  async deletePartition(name: string, force: boolean = false): Promise<boolean> {
    this.ensureInitialized();

    const partition = this.partitions.get(name);
    if (!partition) {
      return false;
    }

    if (partition.entries.length > 0 && !force) {
      throw new Error(`Partition ${name} contains entries. Use force=true to delete.`);
    }

    // Delete all entries in partition
    for (const entry of partition.entries) {
      await this.deleteEntry(entry.id);
    }

    this.partitions.delete(name);
    this.memory.partitions = this.memory.partitions.filter(p => p.id !== partition.id);

    this.emit('memory:partition-deleted', {
      partitionId: partition.id,
      name
    });

    return true;
  }

  getPartition(name: string): MemoryPartition | undefined {
    return this.partitions.get(name);
  }

  getPartitions(): MemoryPartition[] {
    return Array.from(this.partitions.values());
  }

  // ===== BACKUP AND RECOVERY =====

  async createBackup(): Promise<string> {
    this.ensureInitialized();

    const backup: MemoryBackup = {
      timestamp: new Date(),
      version: '1.0.0',
      checksum: '',
      metadata: {
        namespace: this.config.namespace,
        entryCount: this.entries.size,
        partitionCount: this.partitions.size
      },
      entries: Array.from(this.entries.values()),
      partitions: Array.from(this.partitions.values())
    };

    // Calculate checksum
    backup.checksum = this.calculateChecksum(backup);

    const backupId = generateId('backup');
    await this.persistence.saveBackup(backupId, backup);

    this.emit('memory:backup-created', {
      backupId,
      entryCount: backup.entries.length,
      size: JSON.stringify(backup).length
    });

    return backupId;
  }

  async restoreFromBackup(backupId: string): Promise<void> {
    this.ensureInitialized();

    const backup = await this.persistence.loadBackup(backupId);
    if (!backup) {
      throw new Error(`Backup not found: ${backupId}`);
    }

    // Verify checksum
    const calculatedChecksum = this.calculateChecksum(backup);
    if (calculatedChecksum !== backup.checksum) {
      throw new Error('Backup checksum verification failed');
    }

    // Clear current state
    this.entries.clear();
    this.partitions.clear();
    await this.index.clear();

    // Restore entries
    for (const entry of backup.entries) {
      this.entries.set(entry.id, entry);
      await this.index.addEntry(entry);
    }

    // Restore partitions
    for (const partition of backup.partitions) {
      this.partitions.set(partition.name, partition);
    }

    this.memory.partitions = backup.partitions;

    this.emit('memory:backup-restored', {
      backupId,
      entryCount: backup.entries.length,
      partitionCount: backup.partitions.length
    });

    this.logger.info('Restored from backup', {
      backupId,
      entries: backup.entries.length,
      partitions: backup.partitions.length
    });
  }

  // ===== STATISTICS AND MONITORING =====

  getStatistics(): MemoryStatistics {
    const entries = Array.from(this.entries.values());
    const validEntries = entries.filter(e => !this.isExpired(e));

    const entriesByType: Record<MemoryType, number> = {
      knowledge: 0,
      state: 0,
      cache: 0,
      logs: 0,
      results: 0,
      communication: 0,
      configuration: 0,
      metrics: 0
    };

    const entriesByAccess: Record<AccessLevel, number> = {
      private: 0,
      team: 0,
      swarm: 0,
      public: 0,
      system: 0
    };

    let totalSize = 0;
    let oldestEntry = new Date();
    let newestEntry = new Date(0);
    let expiringEntries = 0;

    for (const entry of validEntries) {
      entriesByType[entry.type]++;
      entriesByAccess[entry.accessLevel]++;
      
      const entrySize = this.calculateEntrySize(entry);
      totalSize += entrySize;

      if (entry.createdAt < oldestEntry) {
        oldestEntry = entry.createdAt;
      }

      if (entry.createdAt > newestEntry) {
        newestEntry = entry.createdAt;
      }

      if (entry.expiresAt && entry.expiresAt.getTime() - Date.now() < 24 * 60 * 60 * 1000) {
        expiringEntries++;
      }
    }

    return {
      totalEntries: validEntries.length,
      totalSize,
      partitionCount: this.partitions.size,
      entriesByType,
      entriesByAccess,
      averageSize: validEntries.length > 0 ? totalSize / validEntries.length : 0,
      oldestEntry,
      newestEntry,
      expiringEntries
    };
  }

  async exportMemory(
    options: Partial<{
      format: 'json' | 'csv';
      includeExpired: boolean;
      filter: MemoryQuery;
    }> = {}
  ): Promise<string> {
    this.ensureInitialized();

    let entries = Array.from(this.entries.values());

    if (!options.includeExpired) {
      entries = entries.filter(e => !this.isExpired(e));
    }

    if (options.filter) {
      const filteredResults = await this.query(options.filter);
      const filteredIds = new Set(filteredResults.map(e => e.id));
      entries = entries.filter(e => filteredIds.has(e.id));
    }

    if (options.format === 'csv') {
      return this.entriesToCSV(entries);
    } else {
      return JSON.stringify({
        exported: new Date().toISOString(),
        namespace: this.config.namespace,
        entryCount: entries.length,
        entries: entries.map(e => ({
          ...e,
          value: e.value // Value is already serialized
        }))
      }, null, 2);
    }
  }

  // ===== PRIVATE METHODS =====

  private ensureInitialized(): void {
    if (!this.isInitialized) {
      throw new Error('Memory manager not initialized');
    }
  }

  private async findEntry(key: string, partition?: string): Promise<MemoryEntry | null> {
    for (const entry of this.entries.values()) {
      if (entry.key === key) {
        if (partition) {
          const part = this.partitions.get(partition);
          if (part && part.entries.find(e => e.id === entry.id)) {
            return entry;
          }
        } else {
          return entry;
        }
      }
    }
    return null;
  }

  private async deleteEntry(entryId: string): Promise<boolean> {
    const entry = this.entries.get(entryId);
    if (!entry) {
      return false;
    }

    // Remove from entries
    this.entries.delete(entryId);

    // Remove from partitions
    for (const partition of this.partitions.values()) {
      partition.entries = partition.entries.filter(e => e.id !== entryId);
    }

    // Remove from index
    await this.index.removeEntry(entryId);

    // Remove from cache
    if (this.config.enableCaching) {
      this.cache.delete(entry.key);
    }

    this.emit('memory:deleted', {
      entryId,
      key: entry.key
    });

    return true;
  }

  private isExpired(entry: MemoryEntry): boolean {
    return entry.expiresAt ? entry.expiresAt <= new Date() : false;
  }

  private async validateAccess(
    agent: AgentId,
    operation: 'read' | 'write' | 'delete' | 'share',
    partition?: string
  ): Promise<void> {
    // Implement access control logic here
    // For now, allow all operations
    return;
  }

  private async getOrCreatePartition(name: string): Promise<MemoryPartition> {
    let partition = this.partitions.get(name);
    if (!partition) {
      await this.createPartition(name, {}, !this.isInitialized);
      partition = this.partitions.get(name)!;
    }
    return partition;
  }

  private async serializeValue(value: any): Promise<any> {
    // Apply compression and encryption if enabled
    let serialized = JSON.stringify(value);
    
    if (this.config.enableCompression) {
      // Compression would be implemented here
      // For now, just return the serialized value
    }
    
    if (this.config.enableEncryption) {
      serialized = await this.encryption.encrypt(serialized);
    }
    
    return serialized;
  }

  private async deserializeValue(value: any): Promise<any> {
    let deserialized = value;
    
    if (this.config.enableEncryption) {
      deserialized = await this.encryption.decrypt(deserialized);
    }
    
    if (this.config.enableCompression) {
      // Decompression would be implemented here
      // For now, just use the deserialized value
    }
    
    return JSON.parse(deserialized);
  }

  private calculateEntrySize(entry: MemoryEntry): number {
    return JSON.stringify(entry).length;
  }

  private async enforceMemoryLimits(newEntrySize: number): Promise<void> {
    const stats = this.getStatistics();
    const projectedSize = stats.totalSize + newEntrySize;
    
    if (projectedSize > this.config.maxMemorySize) {
      // Remove expired entries first
      await this.cleanupExpiredEntries();
      
      // If still over limit, remove oldest entries
      const updatedStats = this.getStatistics();
      if (updatedStats.totalSize + newEntrySize > this.config.maxMemorySize) {
        await this.evictOldEntries(newEntrySize);
      }
    }
  }

  private async cleanupExpiredEntries(): Promise<void> {
    const expiredEntries = Array.from(this.entries.values())
      .filter(e => this.isExpired(e));
    
    for (const entry of expiredEntries) {
      await this.deleteEntry(entry.id);
    }
    
    if (expiredEntries.length > 0) {
      this.logger.info('Cleaned up expired entries', { count: expiredEntries.length });
    }
  }

  private async evictOldEntries(requiredSpace: number): Promise<void> {
    const entries = Array.from(this.entries.values())
      .filter(e => !this.isExpired(e))
      .sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
    
    let freedSpace = 0;
    let evictedCount = 0;
    
    for (const entry of entries) {
      if (freedSpace >= requiredSpace) {
        break;
      }
      
      if (entry.accessLevel !== 'system') { // Don't evict system entries
        const entrySize = this.calculateEntrySize(entry);
        await this.deleteEntry(entry.id);
        freedSpace += entrySize;
        evictedCount++;
      }
    }
    
    this.logger.warn('Evicted old entries for space', {
      evictedCount,
      freedSpace,
      requiredSpace
    });
  }

  private calculateChecksum(backup: MemoryBackup): string {
    const content = JSON.stringify({
      entries: backup.entries,
      partitions: backup.partitions
    });
    return crypto.createHash('sha256').update(content).digest('hex');
  }

  private entriesToCSV(entries: MemoryEntry[]): string {
    const headers = ['id', 'key', 'type', 'accessLevel', 'createdAt', 'updatedAt', 'owner', 'tags'];
    const rows = entries.map(entry => [
      entry.id,
      entry.key,
      entry.type,
      entry.accessLevel,
      entry.createdAt.toISOString(),
      entry.updatedAt.toISOString(),
      entry.owner.id,
      entry.tags.join(';')
    ]);
    
    return [headers, ...rows].map(row => row.join(',')).join('\n');
  }

  private async loadMemoryState(): Promise<void> {
    try {
      const state = await this.persistence.loadState();
      if (state) {
        // Load entries
        for (const entry of state.entries || []) {
          this.entries.set(entry.id, entry);
          await this.index.addEntry(entry);
        }
        
        // Load partitions
        for (const partition of state.partitions || []) {
          this.partitions.set(partition.name, partition);
        }
        
        this.memory.partitions = state.partitions || [];
        
        this.logger.info('Loaded memory state', {
          entries: this.entries.size,
          partitions: this.partitions.size
        });
      }
    } catch (error) {
      this.logger.warn('Failed to load memory state', { error });
    }
  }

  private async saveMemoryState(): Promise<void> {
    try {
      const state = {
        namespace: this.config.namespace,
        timestamp: new Date(),
        entries: Array.from(this.entries.values()),
        partitions: Array.from(this.partitions.values())
      };
      
      await this.persistence.saveState(state);
    } catch (error) {
      this.logger.error('Failed to save memory state', { error });
    }
  }

  private async createDefaultPartitions(): Promise<void> {
    const defaultPartitions = [
      { name: 'default', type: 'knowledge' as MemoryType },
      { name: 'system', type: 'configuration' as MemoryType },
      { name: 'cache', type: 'cache' as MemoryType },
      { name: 'logs', type: 'logs' as MemoryType }
    ];
    
    for (const partition of defaultPartitions) {
      if (!this.partitions.has(partition.name)) {
        await this.createPartition(partition.name, { type: partition.type }, true);
      }
    }
  }

  private mergeWithDefaults(config: Partial<MemoryConfig>): MemoryConfig {
    return {
      namespace: 'default',
      persistencePath: './swarm-memory',
      maxMemorySize: 100 * 1024 * 1024, // 100MB
      maxEntrySize: 10 * 1024 * 1024,   // 10MB
      defaultTtl: 24 * 60 * 60 * 1000,  // 24 hours
      enableCompression: false,
      enableEncryption: false,
      consistencyLevel: 'eventual',
      syncInterval: 60000,      // 1 minute
      backupInterval: 3600000,  // 1 hour
      maxBackups: 24,
      enableDistribution: false,
      distributionNodes: [],
      replicationFactor: 1,
      enableCaching: true,
      cacheSize: 1000,
      cacheTtl: 300000, // 5 minutes
      ...config
    };
  }

  private startBackgroundProcesses(): void {
    // Sync process
    if (this.config.syncInterval > 0) {
      this.syncTimer = setInterval(() => {
        this.performSync();
      }, this.config.syncInterval);
    }
    
    // Backup process
    if (this.config.backupInterval > 0) {
      this.backupTimer = setInterval(() => {
        this.createBackup().catch(error => {
          this.logger.error('Background backup failed', { error });
        });
      }, this.config.backupInterval);
    }
    
    // Cleanup process
    this.cleanupTimer = setInterval(() => {
      this.cleanupExpiredEntries();
    }, 60000); // Every minute
  }

  private stopBackgroundProcesses(): void {
    if (this.syncTimer) {
      clearInterval(this.syncTimer);
      this.syncTimer = undefined;
    }
    
    if (this.backupTimer) {
      clearInterval(this.backupTimer);
      this.backupTimer = undefined;
    }
    
    if (this.cleanupTimer) {
      clearInterval(this.cleanupTimer);
      this.cleanupTimer = undefined;
    }
  }

  private async performSync(): Promise<void> {
    try {
      await this.saveMemoryState();
      
      if (this.config.enableDistribution) {
        await this.replication.sync();
      }
    } catch (error) {
      this.logger.error('Background sync failed', { error });
    }
  }

  private setupEventHandlers(): void {
    // Handle replication events
    this.replication.on('entry-received', async (data: any) => {
      const entry = data.entry as MemoryEntry;
      this.entries.set(entry.id, entry);
      await this.index.addEntry(entry);
      
      this.emit('memory:replicated', {
        entryId: entry.id,
        key: entry.key,
        source: data.source
      });
    });
  }
}

// ===== SUPPORTING CLASSES =====

class MemoryIndex {
  private index: Map<string, Set<string>> = new Map();

  async initialize(): Promise<void> {
    // Initialize search index
  }

  async addEntry(entry: MemoryEntry): Promise<void> {
    // Add entry to search index
    this.indexTerms(entry.id, [entry.key, ...entry.tags, entry.type]);
  }

  async updateEntry(entry: MemoryEntry): Promise<void> {
    await this.removeEntry(entry.id);
    await this.addEntry(entry);
  }

  async removeEntry(entryId: string): Promise<void> {
    // Remove from all index terms
    for (const termSet of this.index.values()) {
      termSet.delete(entryId);
    }
  }

  async search(options: MemorySearchOptions): Promise<MemoryEntry[]> {
    // Implement search logic
    return [];
  }

  async clear(): Promise<void> {
    this.index.clear();
  }

  private indexTerms(entryId: string, terms: string[]): void {
    for (const term of terms) {
      const normalizedTerm = term.toLowerCase();
      if (!this.index.has(normalizedTerm)) {
        this.index.set(normalizedTerm, new Set());
      }
      this.index.get(normalizedTerm)!.add(entryId);
    }
  }
}

class MemoryCache {
  private cache: Map<string, { entry: MemoryEntry; expiry: number }> = new Map();
  private maxSize: number;
  private ttl: number;

  constructor(maxSize: number, ttl: number) {
    this.maxSize = maxSize;
    this.ttl = ttl;
  }

  set(key: string, entry: MemoryEntry): void {
    // Evict if at capacity
    if (this.cache.size >= this.maxSize) {
      const oldestKey = this.cache.keys().next().value;
      this.cache.delete(oldestKey);
    }
    
    this.cache.set(key, {
      entry,
      expiry: Date.now() + this.ttl
    });
  }

  get(key: string): MemoryEntry | null {
    const cached = this.cache.get(key);
    if (!cached) {
      return null;
    }
    
    if (Date.now() > cached.expiry) {
      this.cache.delete(key);
      return null;
    }
    
    return cached.entry;
  }

  delete(key: string): void {
    this.cache.delete(key);
  }
}

class MemoryReplication extends EventEmitter {
  private config: MemoryConfig;

  constructor(config: MemoryConfig) {
    super();
    this.config = config;
  }

  async initialize(): Promise<void> {
    // Initialize replication
  }

  async shutdown(): Promise<void> {
    // Shutdown replication
  }

  async replicate(entry: MemoryEntry): Promise<void> {
    // Replicate entry to other nodes
  }

  async synchronizeWith(targetNode: string, options: any): Promise<void> {
    // Synchronize with target node
  }

  async sync(): Promise<void> {
    // Perform background sync
  }
}

class MemoryPersistence {
  private config: MemoryConfig;

  constructor(config: MemoryConfig) {
    this.config = config;
  }

  async initialize(): Promise<void> {
    await fs.mkdir(this.config.persistencePath, { recursive: true });
  }

  async shutdown(): Promise<void> {
    // Shutdown persistence
  }

  async saveState(state: any): Promise<void> {
    const statePath = path.join(this.config.persistencePath, 'state.json');
    await fs.writeFile(statePath, JSON.stringify(state, null, 2));
  }

  async loadState(): Promise<any> {
    try {
      const statePath = path.join(this.config.persistencePath, 'state.json');
      const content = await fs.readFile(statePath, 'utf-8');
      return JSON.parse(content);
    } catch (error) {
      return null;
    }
  }

  async saveBackup(backupId: string, backup: MemoryBackup): Promise<void> {
    const backupPath = path.join(this.config.persistencePath, 'backups', `${backupId}.json`);
    await fs.mkdir(path.dirname(backupPath), { recursive: true });
    await fs.writeFile(backupPath, JSON.stringify(backup, null, 2));
  }

  async loadBackup(backupId: string): Promise<MemoryBackup | null> {
    try {
      const backupPath = path.join(this.config.persistencePath, 'backups', `${backupId}.json`);
      const content = await fs.readFile(backupPath, 'utf-8');
      return JSON.parse(content);
    } catch (error) {
      return null;
    }
  }
}

class MemoryEncryption {
  private config: MemoryConfig;

  constructor(config: MemoryConfig) {
    this.config = config;
  }

  async initialize(): Promise<void> {
    // Initialize encryption
  }

  async shutdown(): Promise<void> {
    // Shutdown encryption
  }

  async encrypt(data: string): Promise<string> {
    // Implement encryption
    return data;
  }

  async decrypt(data: string): Promise<string> {
    // Implement decryption
    return data;
  }
}

export default SwarmMemoryManager;