import { getErrorMessage } from '../utils/error-handler.js';
/**
 * Distributed memory system with sharing capabilities
 */

import { EventEmitter } from 'node:events';
import type { ILogger } from '../core/logger.js';
import type { IEventBus } from '../core/event-bus.js';
import type { 
  SwarmMemory, 
  MemoryPartition, 
  MemoryEntry, 
  MemoryType, 
  AccessLevel, 
  ConsistencyLevel,
  MemoryPermissions,
  AgentId
} from '../swarm/types.js';
import { generateId } from '../utils/helpers.js';

export interface DistributedMemoryConfig {
  namespace: string;
  distributed: boolean;
  consistency: ConsistencyLevel;
  replicationFactor: number;
  syncInterval: number;
  maxMemorySize: number;
  compressionEnabled: boolean;
  encryptionEnabled: boolean;
  backupEnabled: boolean;
  persistenceEnabled: boolean;
  shardingEnabled: boolean;
  cacheSize: number;
  cacheTtl: number;
  backend?: string;
  timeout?: number;
  retryAttempts?: number;
}

export interface MemoryNode {
  id: string;
  address: string;
  port: number;
  status: 'online' | 'offline' | 'syncing' | 'failed';
  lastSeen: Date;
  partitions: string[];
  load: number;
  capacity: number;
}

export interface SyncOperation {
  id: string;
  type: 'create' | 'update' | 'delete' | 'batch';
  partition: string;
  entry?: MemoryEntry;
  entries?: MemoryEntry[];
  timestamp: Date;
  version: number;
  origin: string;
  targets: string[];
  status: 'pending' | 'in_progress' | 'completed' | 'failed';
}

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

export interface MemoryStatistics {
  totalEntries: number;
  totalSize: number;
  partitionCount: number;
  nodeCount: number;
  replicationHealth: number;
  syncOperations: {
    pending: number;
    completed: number;
    failed: number;
  };
  performance: {
    readLatency: number;
    writeLatency: number;
    syncLatency: number;
    throughput: number;
  };
  utilization: {
    memoryUsage: number;
    diskUsage: number;
    networkUsage: number;
  };
}

/**
 * Distributed memory system for sharing data across swarm agents
 */
export class DistributedMemorySystem extends EventEmitter {
  private logger: ILogger;
  private eventBus: IEventBus;
  private config: DistributedMemoryConfig;
  
  // Storage
  private partitions = new Map<string, MemoryPartition>();
  private entries = new Map<string, MemoryEntry>();
  private cache = new Map<string, { entry: MemoryEntry; expiry: number }>();
  
  // Distribution
  private nodes = new Map<string, MemoryNode>();
  private localNodeId: string;
  private syncQueue: SyncOperation[] = [];
  private replicationMap = new Map<string, string[]>(); // entryId -> nodeIds
  
  // Synchronization
  private syncInterval?: NodeJS.Timeout;
  private vectorClock = new Map<string, number>();
  private conflictResolver?: (local: MemoryEntry, remote: MemoryEntry) => MemoryEntry;
  
  // Performance tracking
  private statistics: MemoryStatistics;
  private operationMetrics = new Map<string, { count: number; totalTime: number }>();

  constructor(
    config: Partial<DistributedMemoryConfig>,
    logger: ILogger,
    eventBus: IEventBus
  ) {
    super();
    this.logger = logger;
    this.eventBus = eventBus;
    
    this.config = {
      namespace: 'default',
      distributed: true,
      consistency: 'eventual',
      replicationFactor: 3,
      syncInterval: 5000,
      maxMemorySize: 1024 * 1024 * 1024, // 1GB
      compressionEnabled: true,
      encryptionEnabled: false,
      backupEnabled: true,
      persistenceEnabled: true,
      shardingEnabled: true,
      cacheSize: 10000,
      cacheTtl: 300000, // 5 minutes
      ...config
    };

    this.localNodeId = generateId('memory-node');
    this.statistics = this.initializeStatistics();
    
    this.setupEventHandlers();
  }

  private setupEventHandlers(): void {
    this.eventBus.on('memory:sync-request', (data) => {
      this.handleSyncRequest(data);
    });

    this.eventBus.on('memory:node-joined', (data) => {
      this.handleNodeJoined(data);
    });

    this.eventBus.on('memory:node-left', (data) => {
      this.handleNodeLeft(data);
    });

    this.eventBus.on('memory:conflict-detected', (data) => {
      this.handleConflict(data);
    });
  }

  async initialize(): Promise<void> {
    this.logger.info('Initializing distributed memory system', {
      nodeId: this.localNodeId,
      namespace: this.config.namespace,
      distributed: this.config.distributed
    });

    // Register local node
    const localNode: MemoryNode = {
      id: this.localNodeId,
      address: 'localhost',
      port: 8080,
      status: 'online',
      lastSeen: new Date(),
      partitions: [],
      load: 0,
      capacity: this.config.maxMemorySize
    };

    this.nodes.set(this.localNodeId, localNode);

    // Initialize default partitions
    await this.createPartition('knowledge', 'knowledge');
    await this.createPartition('state', 'state');
    await this.createPartition('cache', 'cache');
    await this.createPartition('results', 'results');

    // Start synchronization if distributed
    if (this.config.distributed) {
      this.startSynchronization();
    }

    // Load persisted data if enabled
    if (this.config.persistenceEnabled) {
      await this.loadPersistedData();
    }

    this.emit('memory:initialized', { nodeId: this.localNodeId });
  }

  async shutdown(): Promise<void> {
    this.logger.info('Shutting down distributed memory system');

    // Stop synchronization
    if (this.syncInterval) {
      clearInterval(this.syncInterval);
    }

    // Complete pending sync operations
    await this.completePendingSyncOperations();

    // Persist data if enabled
    if (this.config.persistenceEnabled) {
      await this.persistData();
    }

    // Clear caches
    this.cache.clear();
    this.partitions.clear();
    this.entries.clear();

    this.emit('memory:shutdown', { nodeId: this.localNodeId });
  }

  // === PARTITION MANAGEMENT ===

  async createPartition(
    name: string, 
    type: MemoryType,
    options: {
      maxSize?: number;
      ttl?: number;
      readOnly?: boolean;
      shared?: boolean;
      indexed?: boolean;
      compressed?: boolean;
    } = {}
  ): Promise<string> {
    const partitionId = generateId('partition');
    
    const partition: MemoryPartition = {
      id: partitionId,
      name,
      type,
      entries: [],
      maxSize: options.maxSize || this.config.maxMemorySize / 10,
      ttl: options.ttl,
      readOnly: options.readOnly || false,
      shared: options.shared !== false, // Default to shared
      indexed: options.indexed || false,
      compressed: options.compressed || this.config.compressionEnabled
    };

    this.partitions.set(partitionId, partition);

    // Update local node partition list
    const localNode = this.nodes.get(this.localNodeId)!;
    localNode.partitions.push(partitionId);

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

    // Sync with other nodes if distributed
    if (this.config.distributed) {
      await this.syncPartitionCreation(partition);
    }

    return partitionId;
  }

  async deletePartition(partitionId: string): Promise<void> {
    const partition = this.partitions.get(partitionId);
    if (!partition) {
      throw new Error(`Partition ${partitionId} not found`);
    }

    // Delete all entries in partition
    const entriesToDelete = Array.from(this.entries.values())
      .filter(entry => this.getEntryPartition(entry.id) === partitionId);

    for (const entry of entriesToDelete) {
      await this.deleteEntry(entry.id);
    }

    // Remove partition
    this.partitions.delete(partitionId);

    // Update local node
    const localNode = this.nodes.get(this.localNodeId)!;
    localNode.partitions = localNode.partitions.filter(p => p !== partitionId);

    this.logger.info('Deleted partition', { partitionId });
    this.emit('memory:partition-deleted', { partitionId });

    // Sync with other nodes if distributed
    if (this.config.distributed) {
      await this.syncPartitionDeletion(partitionId);
    }
  }

  // === ENTRY OPERATIONS ===

  async store(
    key: string,
    value: any,
    options: {
      type?: string;
      tags?: string[];
      owner?: AgentId;
      accessLevel?: AccessLevel;
      partition?: string;
      ttl?: number;
      replicate?: boolean;
    } = {}
  ): Promise<string> {
    const startTime = Date.now();
    
    try {
      const entryId = generateId('entry');
      const now = new Date();
      
      // Determine partition
      const partitionId = options.partition || this.selectPartition(options.type || 'knowledge');
      const partition = this.partitions.get(partitionId);
      
      if (!partition) {
        throw new Error(`Partition ${partitionId} not found`);
      }

      if (partition.readOnly) {
        throw new Error('Cannot write to read-only partition');
      }

      // Check partition capacity
      if (this.getPartitionSize(partitionId) >= partition.maxSize) {
        await this.evictOldEntries(partitionId);
      }

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

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

      // Update cache
      this.updateCache(entryId, entry);

      // Update vector clock
      this.incrementVectorClock(this.localNodeId);

      this.logger.debug('Stored entry', { entryId, key, partition: partitionId });
      this.emit('memory:entry-stored', { entry });

      // Replicate if distributed and requested
      if (this.config.distributed && options.replicate !== false) {
        await this.replicateEntry(entry);
      }

      this.recordMetric('store', Date.now() - startTime);
      return entryId;

    } catch (error) {
      this.recordMetric('store-error', Date.now() - startTime);
      throw error;
    }
  }

  async retrieve(
    key: string,
    options: {
      partition?: string;
      consistency?: ConsistencyLevel;
      maxAge?: number;
    } = {}
  ): Promise<MemoryEntry | null> {
    const startTime = Date.now();
    
    try {
      // Check cache first
      const cached = this.getCachedEntry(key);
      if (cached && this.isCacheValid(cached)) {
        this.recordMetric('retrieve-cache', Date.now() - startTime);
        return cached.entry;
      }

      // Search in specified partition or all partitions
      const partitions = options.partition 
        ? [this.partitions.get(options.partition)].filter(Boolean)
        : Array.from(this.partitions.values());

      for (const partition of partitions) {
        const entry = partition!.entries.find(e => e.key === key);
        if (entry) {
          // Check if entry is expired
          if (entry.expiresAt && entry.expiresAt < new Date()) {
            await this.deleteEntry(entry.id);
            continue;
          }

          // Check access permissions
          if (!this.checkAccess(entry, 'read')) {
            continue;
          }

          // Apply consistency model
          if (this.config.distributed && options.consistency === 'strong') {
            const latestEntry = await this.ensureConsistency(entry);
            this.updateCache(latestEntry.id, latestEntry);
            this.recordMetric('retrieve', Date.now() - startTime);
            return latestEntry;
          }

          this.updateCache(entry.id, entry);
          this.recordMetric('retrieve', Date.now() - startTime);
          return entry;
        }
      }

      // Not found locally, try remote nodes if distributed
      if (this.config.distributed) {
        const remoteEntry = await this.retrieveFromRemote(key, options);
        if (remoteEntry) {
          this.recordMetric('retrieve-remote', Date.now() - startTime);
          return remoteEntry;
        }
      }

      this.recordMetric('retrieve-miss', Date.now() - startTime);
      return null;

    } catch (error) {
      this.recordMetric('retrieve-error', Date.now() - startTime);
      throw error;
    }
  }

  async update(
    key: string,
    value: any,
    options: {
      partition?: string;
      merge?: boolean;
      version?: number;
    } = {}
  ): Promise<boolean> {
    const startTime = Date.now();
    
    try {
      const entry = await this.retrieve(key, { partition: options.partition });
      if (!entry) {
        this.recordMetric('update-not-found', Date.now() - startTime);
        return false;
      }

      // Check access permissions
      if (!this.checkAccess(entry, 'write')) {
        throw new Error('Access denied for update operation');
      }

      // Version check for optimistic locking
      if (options.version && entry.version !== options.version) {
        throw new Error('Version conflict: entry has been modified');
      }

      // Update entry
      const partition = this.partitions.get(this.getEntryPartition(entry.id))!;
      
      entry.value = options.merge 
        ? await this.mergeValues(entry.value, value, partition)
        : await this.processValue(value, partition);
      
      entry.updatedAt = new Date();
      entry.version++;

      // Update cache
      this.updateCache(entry.id, entry);

      // Update vector clock
      this.incrementVectorClock(this.localNodeId);

      this.logger.debug('Updated entry', { entryId: entry.id, key });
      this.emit('memory:entry-updated', { entry });

      // Sync with other nodes if distributed
      if (this.config.distributed) {
        await this.syncEntryUpdate(entry);
      }

      this.recordMetric('update', Date.now() - startTime);
      return true;

    } catch (error) {
      this.recordMetric('update-error', Date.now() - startTime);
      throw error;
    }
  }

  async deleteEntry(entryId: string): Promise<boolean> {
    const startTime = Date.now();
    
    try {
      const entry = this.entries.get(entryId);
      if (!entry) {
        this.recordMetric('delete-not-found', Date.now() - startTime);
        return false;
      }

      // Check access permissions
      if (!this.checkAccess(entry, 'delete')) {
        throw new Error('Access denied for delete operation');
      }

      // Remove from partition
      const partitionId = this.getEntryPartition(entryId);
      const partition = this.partitions.get(partitionId);
      if (partition) {
        partition.entries = partition.entries.filter(e => e.id !== entryId);
      }

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

      // Remove from cache
      this.removeFromCache(entry.key);

      // Update vector clock
      this.incrementVectorClock(this.localNodeId);

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

      // Sync with other nodes if distributed
      if (this.config.distributed) {
        await this.syncEntryDeletion(entryId);
      }

      this.recordMetric('delete', Date.now() - startTime);
      return true;

    } catch (error) {
      this.recordMetric('delete-error', Date.now() - startTime);
      throw error;
    }
  }

  // === QUERY OPERATIONS ===

  async query(query: MemoryQuery): Promise<MemoryEntry[]> {
    const startTime = Date.now();
    
    try {
      let results: MemoryEntry[] = [];

      // Get relevant partitions
      const partitions = query.partition
        ? [this.partitions.get(query.partition)].filter(Boolean)
        : Array.from(this.partitions.values());

      for (const partition of partitions) {
        for (const entry of partition!.entries) {
          if (this.matchesQuery(entry, query)) {
            results.push(entry);
          }
        }
      }

      // Apply sorting
      if (query.sortBy) {
        results.sort((a, b) => {
          const aVal = this.getNestedProperty(a, query.sortBy!);
          const bVal = this.getNestedProperty(b, query.sortBy!);
          const order = query.sortOrder === 'desc' ? -1 : 1;
          
          if (aVal < bVal) return -1 * order;
          if (aVal > bVal) return 1 * order;
          return 0;
        });
      }

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

      this.recordMetric('query', Date.now() - startTime);
      return results;

    } catch (error) {
      this.recordMetric('query-error', Date.now() - startTime);
      throw error;
    }
  }

  /**
   * Query entries by type
   */
  async queryByType(type: string, namespace?: string): Promise<MemoryEntry[]> {
    return this.query({
      filter: { type },
      namespace
    });
  }

  // === SYNCHRONIZATION ===

  private startSynchronization(): void {
    this.syncInterval = setInterval(() => {
      this.performSync();
    }, this.config.syncInterval);

    this.logger.info('Started synchronization', { 
      interval: this.config.syncInterval,
      consistency: this.config.consistency 
    });
  }

  private async performSync(): Promise<void> {
    try {
      // Process pending sync operations
      await this.processSyncQueue();

      // Send heartbeat to other nodes
      await this.sendHeartbeat();

      // Check for conflicts and resolve them
      await this.detectAndResolveConflicts();

      // Update statistics
      this.updateStatistics();

    } catch (error) {
      this.logger.error('Sync error', error);
    }
  }

  private async processSyncQueue(): Promise<void> {
    const pendingOps = this.syncQueue.filter(op => op.status === 'pending');
    
    for (const operation of pendingOps) {
      try {
        operation.status = 'in_progress';
        await this.executeSyncOperation(operation);
        operation.status = 'completed';
        
        this.statistics.syncOperations.completed++;
      } catch (error) {
        operation.status = 'failed';
        this.statistics.syncOperations.failed++;
        this.logger.error('Sync operation failed', { operation, error });
      }
    }

    // Remove completed/failed operations older than 1 hour
    const cutoff = new Date(Date.now() - 3600000);
    this.syncQueue = this.syncQueue.filter(op => 
      op.status === 'pending' || op.timestamp > cutoff
    );
  }

  // === UTILITY METHODS ===

  private async processValue(value: any, partition: MemoryPartition): Promise<any> {
    if (partition.compressed && this.config.compressionEnabled) {
      return this.compressValue(value);
    }
    return value;
  }

  private async mergeValues(oldValue: any, newValue: any, partition: MemoryPartition): Promise<any> {
    // Simple merge strategy - can be enhanced
    if (typeof oldValue === 'object' && typeof newValue === 'object') {
      return { ...oldValue, ...newValue };
    }
    return newValue;
  }

  private compressValue(value: any): any {
    // Placeholder for compression logic
    return value;
  }

  private checkAccess(entry: MemoryEntry, operation: 'read' | 'write' | 'delete'): boolean {
    // Simplified access control - can be enhanced
    return true;
  }

  private selectPartition(type: string): string {
    // Simple partition selection based on type
    for (const [id, partition] of this.partitions) {
      if (partition.type === type) {
        return id;
      }
    }
    
    // Default to first available partition
    return Array.from(this.partitions.keys())[0] || '';
  }

  private getPartitionSize(partitionId: string): number {
    const partition = this.partitions.get(partitionId);
    if (!partition) return 0;
    
    return partition.entries.reduce((size, entry) => {
      return size + JSON.stringify(entry).length;
    }, 0);
  }

  private getEntryPartition(entryId: string): string {
    for (const [partitionId, partition] of this.partitions) {
      if (partition.entries.some(e => e.id === entryId)) {
        return partitionId;
      }
    }
    return '';
  }

  private updateCache(entryId: string, entry: MemoryEntry): void {
    if (this.cache.size >= this.config.cacheSize) {
      this.evictCache();
    }
    
    this.cache.set(entry.key, {
      entry: { ...entry },
      expiry: Date.now() + this.config.cacheTtl
    });
  }

  private getCachedEntry(key: string): { entry: MemoryEntry; expiry: number } | null {
    return this.cache.get(key) || null;
  }

  private isCacheValid(cached: { entry: MemoryEntry; expiry: number }): boolean {
    return cached.expiry > Date.now();
  }

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

  private evictCache(): void {
    // Simple LRU eviction - remove oldest entries
    const entries = Array.from(this.cache.entries());
    entries.sort((a, b) => a[1].expiry - b[1].expiry);
    
    const toRemove = entries.slice(0, Math.floor(this.config.cacheSize * 0.1));
    toRemove.forEach(([key]) => this.cache.delete(key));
  }

  private async evictOldEntries(partitionId: string): Promise<void> {
    const partition = this.partitions.get(partitionId);
    if (!partition) return;

    // Sort by last access time and remove oldest 10%
    const entries = partition.entries.sort((a, b) => 
      a.updatedAt.getTime() - b.updatedAt.getTime()
    );
    
    const toRemove = entries.slice(0, Math.floor(entries.length * 0.1));
    for (const entry of toRemove) {
      await this.deleteEntry(entry.id);
    }
  }

  private matchesQuery(entry: MemoryEntry, query: MemoryQuery): boolean {
    if (query.type && entry.type !== query.type) return false;
    if (query.owner && entry.owner.id !== query.owner.id) return false;
    if (query.accessLevel && entry.accessLevel !== query.accessLevel) return false;
    if (query.createdAfter && entry.createdAt < query.createdAfter) return false;
    if (query.updatedAfter && entry.updatedAt < query.updatedAfter) return false;
    
    if (query.tags && query.tags.length > 0) {
      const hasAllTags = query.tags.every(tag => entry.tags.includes(tag));
      if (!hasAllTags) return false;
    }
    
    return true;
  }

  private getNestedProperty(obj: any, path: string): any {
    return path.split('.').reduce((current, key) => current?.[key], obj);
  }

  private incrementVectorClock(nodeId: string): void {
    const current = this.vectorClock.get(nodeId) || 0;
    this.vectorClock.set(nodeId, current + 1);
  }

  private recordMetric(operation: string, duration: number): void {
    const current = this.operationMetrics.get(operation) || { count: 0, totalTime: 0 };
    current.count++;
    current.totalTime += duration;
    this.operationMetrics.set(operation, current);
  }

  private initializeStatistics(): MemoryStatistics {
    return {
      totalEntries: 0,
      totalSize: 0,
      partitionCount: 0,
      nodeCount: 1,
      replicationHealth: 1.0,
      syncOperations: {
        pending: 0,
        completed: 0,
        failed: 0
      },
      performance: {
        readLatency: 0,
        writeLatency: 0,
        syncLatency: 0,
        throughput: 0
      },
      utilization: {
        memoryUsage: 0,
        diskUsage: 0,
        networkUsage: 0
      }
    };
  }

  private updateStatistics(): void {
    this.statistics.totalEntries = this.entries.size;
    this.statistics.partitionCount = this.partitions.size;
    this.statistics.nodeCount = this.nodes.size;
    
    // Calculate performance metrics
    const readMetrics = this.operationMetrics.get('retrieve') || { count: 0, totalTime: 0 };
    const writeMetrics = this.operationMetrics.get('store') || { count: 0, totalTime: 0 };
    
    this.statistics.performance.readLatency = readMetrics.count > 0 
      ? readMetrics.totalTime / readMetrics.count : 0;
    this.statistics.performance.writeLatency = writeMetrics.count > 0 
      ? writeMetrics.totalTime / writeMetrics.count : 0;
  }

  // === DISTRIBUTED OPERATIONS (Placeholders) ===

  private async replicateEntry(entry: MemoryEntry): Promise<void> {
    // Implementation for replication to other nodes
  }

  private async syncPartitionCreation(partition: MemoryPartition): Promise<void> {
    // Implementation for syncing partition creation
  }

  private async syncPartitionDeletion(partitionId: string): Promise<void> {
    // Implementation for syncing partition deletion
  }

  private async syncEntryUpdate(entry: MemoryEntry): Promise<void> {
    // Implementation for syncing entry updates
  }

  private async syncEntryDeletion(entryId: string): Promise<void> {
    // Implementation for syncing entry deletion
  }

  private async retrieveFromRemote(key: string, options: any): Promise<MemoryEntry | null> {
    // Implementation for retrieving from remote nodes
    return null;
  }

  private async ensureConsistency(entry: MemoryEntry): Promise<MemoryEntry> {
    // Implementation for ensuring strong consistency
    return entry;
  }

  private async sendHeartbeat(): Promise<void> {
    // Implementation for sending heartbeat to other nodes
  }

  private async detectAndResolveConflicts(): Promise<void> {
    // Implementation for conflict detection and resolution
  }

  private async executeSyncOperation(operation: SyncOperation): Promise<void> {
    // Implementation for executing sync operations
  }

  private async completePendingSyncOperations(): Promise<void> {
    // Implementation for completing pending operations
  }

  private async loadPersistedData(): Promise<void> {
    // Implementation for loading persisted data
  }

  private async persistData(): Promise<void> {
    // Implementation for persisting data
  }

  private handleSyncRequest(data: any): void {
    // Handle sync requests from other nodes
  }

  private handleNodeJoined(data: any): void {
    // Handle new node joining
  }

  private handleNodeLeft(data: any): void {
    // Handle node leaving
  }

  private handleConflict(data: any): void {
    // Handle conflict resolution
  }

  // === PUBLIC API ===

  getStatistics(): MemoryStatistics {
    this.updateStatistics();
    return { ...this.statistics };
  }

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

  getNodes(): MemoryNode[] {
    return Array.from(this.nodes.values());
  }

  async backup(): Promise<string> {
    // Create backup of all data
    const backup = {
      timestamp: new Date(),
      partitions: Array.from(this.partitions.values()),
      entries: Array.from(this.entries.values()),
      metadata: {
        version: '1.0',
        nodeId: this.localNodeId,
        config: this.config
      }
    };

    return JSON.stringify(backup);
  }

  async restore(backupData: string): Promise<void> {
    // Restore from backup
    const backup = JSON.parse(backupData);
    
    // Clear current data
    this.partitions.clear();
    this.entries.clear();
    this.cache.clear();

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

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

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

  async clear(): Promise<void> {
    this.partitions.clear();
    this.entries.clear();
    this.cache.clear();
    this.syncQueue = [];
    this.statistics = this.initializeStatistics();
    
    this.logger.info('Cleared all memory data');
    this.emit('memory:cleared');
  }
}