/**
 * Super-Enhanced Memory System Implementation
 * Based on the specification provided by JC Beasley
 */

// Memory Categories
const MEMORY_CATEGORIES = {
  IDENTITY: 'identity',
  PREFERENCES: 'preferences',
  GOALS: 'goals',
  KNOWLEDGE: 'knowledge',
  EPISODIC: 'episodic',
  CORRECTION: 'correction'
};

// Memory Structure
class MemoryItem {
  constructor(key, category, content, importance = 5, tags = []) {
    this.key = key;
    this.category = category;
    this.content = content;
    this.importance = importance;
    this.tags = tags;
    this.created = new Date().toISOString();
    this.updated = new Date().toISOString();
    this.access_count = 0;
    this.expires = null;
    this.confidence = 1.0;
  }
}

// Memory Index
class MemoryIndex {
  constructor() {
    this.index = {};
  }

  async updateIndex(key, memory) {
    try {
      // In a real implementation, this would use window.storage
      // For now, we'll simulate it with file-based storage
      const indexPath = '/home/jcbeasley/.openclaw/workspace/memory/_index.json';
      
      // Load existing index
      let index = {};
      try {
        const indexContent = await this.readFile(indexPath);
        if (indexContent) {
          index = JSON.parse(indexContent);
        }
      } catch (e) {
        // Index doesn't exist yet, start fresh
      }

      // Update index
      index[key] = {
        category: memory.category,
        importance: memory.importance,
        updated: memory.updated,
        tags: memory.tags
      };

      // Save index
      await this.writeFile(indexPath, JSON.stringify(index, null, 2));
    } catch (e) {
      console.error(`Failed to update memory index for ${key}:`, e);
    }
  }

  async readFile(path) {
    // Simulate file reading
    // In real implementation, this would use actual file system or storage API
    return null;
  }

  async writeFile(path, content) {
    // Simulate file writing
    // In real implementation, this would use actual file system or storage API
  }
}

// Memory Manager
class MemoryManager {
  constructor() {
    this.index = new MemoryIndex();
    this.storagePrefix = 'mem:';
  }

  // Create a memory item
  async createMemory(key, category, content, importance = 5, tags = []) {
    const memory = new MemoryItem(key, category, content, importance, tags);
    await this.saveMemory(key, memory);
    return memory;
  }

  // Save memory to storage
  async saveMemory(key, memory) {
    try {
      // In a real implementation, this would use window.storage.set
      // For now, we'll store in our project memory directory
      const memoryPath = `/home/jcbeasley/.openclaw/workspace/memory/items/${key.replace(':', '_')}.json`;
      
      // Ensure directory exists
      await this.ensureDirectory('/home/jcbeasley/.openclaw/workspace/memory/items/');
      
      // Save memory item
      const fs = require('fs').promises;
      await fs.writeFile(memoryPath, JSON.stringify(memory, null, 2));
      
      // Update index
      await this.index.updateIndex(key, memory);
      
      console.log(`Memory saved: ${key}`);
    } catch (e) {
      console.error(`Failed to save memory ${key}:`, e);
    }
  }

  // Load memory from storage
  async loadMemory(key) {
    try {
      // In a real implementation, this would use window.storage.get
      const memoryPath = `/home/jcbeasley/.openclaw/workspace/memory/items/${key.replace(':', '_')}.json`;
      
      const fs = require('fs').promises;
      const content = await fs.readFile(memoryPath, 'utf8');
      const memory = JSON.parse(content);
      
      // Update access count
      memory.access_count = (memory.access_count || 0) + 1;
      memory.updated = new Date().toISOString();
      await this.saveMemory(key, memory);
      
      return memory;
    } catch (e) {
      console.error(`Failed to load memory ${key}:`, e);
      return null;
    }
  }

  // Update existing memory (merge, don't overwrite)
  async updateMemory(key, newContent) {
    try {
      let memory = await this.loadMemory(key);
      
      if (memory) {
        // Merge content
        if (typeof memory.content === 'object' && typeof newContent === 'object') {
          memory.content = { ...memory.content, ...newContent };
        } else {
          memory.content = newContent;
        }
        
        memory.updated = new Date().toISOString();
        memory.access_count = (memory.access_count || 0) + 1;
        
        await this.saveMemory(key, memory);
        return memory;
      } else {
        // Create new memory
        return await this.createMemory(key, MEMORY_CATEGORIES.KNOWLEDGE, newContent);
      }
    } catch (e) {
      console.error(`Failed to update memory ${key}:`, e);
      return null;
    }
  }

  // Delete memory
  async deleteMemory(key) {
    try {
      // In a real implementation, this would use window.storage.delete
      const memoryPath = `/home/jcbeasley/.openclaw/workspace/memory/items/${key.replace(':', '_')}.json`;
      
      const fs = require('fs').promises;
      await fs.unlink(memoryPath);
      
      console.log(`Memory deleted: ${key}`);
    } catch (e) {
      console.error(`Failed to delete memory ${key}:`, e);
    }
  }

  // Expire memory (soft delete)
  async expireMemory(key) {
    try {
      let memory = await this.loadMemory(key);
      if (memory) {
        memory.expires = new Date().toISOString();
        await this.saveMemory(key, memory);
      }
    } catch (e) {
      console.error(`Failed to expire memory ${key}:`, e);
    }
  }

  // Ensure directory exists
  async ensureDirectory(dirPath) {
    const fs = require('fs').promises;
    try {
      await fs.mkdir(dirPath, { recursive: true });
    } catch (e) {
      // Directory might already exist
    }
  }

  // Proactive memory behaviors
  async conversationStart() {
    console.log("Starting conversation with proactive memory loading...");
    
    // Load memory index
    const indexPath = '/home/jcbeasley/.openclaw/workspace/memory/_index.json';
    let index = {};
    try {
      const fs = require('fs').promises;
      const indexContent = await fs.readFile(indexPath, 'utf8');
      index = JSON.parse(indexContent);
    } catch (e) {
      // Index doesn't exist yet
    }

    // Load high importance memories (>= 7)
    const highImportanceMemories = [];
    for (const [key, metadata] of Object.entries(index)) {
      if (metadata.importance >= 7) {
        const memory = await this.loadMemory(key);
        if (memory) {
          highImportanceMemories.push(memory);
        }
      }
    }

    console.log(`Loaded ${highImportanceMemories.length} high-importance memories`);
    return highImportanceMemories;
  }

  // Auto-capture memories during conversation
  async autoCapture(userMessage, context) {
    // User states their name
    if (userMessage.toLowerCase().includes("my name is") || userMessage.toLowerCase().includes("i'm") || userMessage.toLowerCase().includes("i am")) {
      const nameMatch = userMessage.match(/(?:my name is|i'm|i am)\s+([a-zA-Z]+)/i);
      if (nameMatch) {
        await this.createMemory('mem:identity:name', MEMORY_CATEGORIES.IDENTITY, nameMatch[1], 10, ['name']);
      }
    }

    // User corrects information
    if (userMessage.toLowerCase().includes("actually") || userMessage.toLowerCase().includes("no,") || userMessage.toLowerCase().includes("correction")) {
      await this.createMemory(`mem:correction:${Date.now()}`, MEMORY_CATEGORIES.CORRECTION, userMessage, 8, ['correction']);
    }

    // User expresses preferences
    if (userMessage.toLowerCase().includes("prefer") || userMessage.toLowerCase().includes("like") || userMessage.toLowerCase().includes("want")) {
      const prefMatch = userMessage.match(/(?:prefer|like|want)\s+(.+?)(?:\.|$)/i);
      if (prefMatch) {
        await this.createMemory(`mem:pref:${prefMatch[1].toLowerCase().replace(/\s+/g, '_')}`, MEMORY_CATEGORIES.PREFERENCES, prefMatch[1], 7, ['preference']);
      }
    }

    // User mentions goals/projects
    if (userMessage.toLowerCase().includes("goal") || userMessage.toLowerCase().includes("project") || userMessage.toLowerCase().includes("task")) {
      const goalMatch = userMessage.match(/(?:goal|project|task)\s+(.+?)(?:\.|$)/i);
      if (goalMatch) {
        await this.createMemory(`mem:goal:${goalMatch[1].toLowerCase().replace(/\s+/g, '_')}`, MEMORY_CATEGORIES.GOALS, goalMatch[1], 8, ['goal']);
      }
    }
  }

  // Special commands handling
  async handleSpecialCommand(command) {
    switch (command.toLowerCase()) {
      case "what do you remember about me?":
        return await this.listIdentityMemories();
      case "show my memory profile":
        return await this.showMemoryProfile();
      default:
        if (command.toLowerCase().startsWith("remember that")) {
          const content = command.substring("remember that".length).trim();
          return await this.createMemory(`mem:episodic:${Date.now()}`, MEMORY_CATEGORIES.EPISODIC, content, 9, ['user-requested']);
        } else if (command.toLowerCase().startsWith("forget")) {
          const tag = command.substring("forget".length).trim();
          return await this.forgetMemoriesWithTag(tag);
        } else if (command.toLowerCase().startsWith("update your memory:")) {
          const content = command.substring("update your memory:".length).trim();
          return await this.updateMemoryByContent(content);
        }
    }
  }

  async listIdentityMemories() {
    // List high-importance identity memories
    const indexPath = '/home/jcbeasley/.openclaw/workspace/memory/_index.json';
    let index = {};
    try {
      const fs = require('fs').promises;
      const indexContent = await fs.readFile(indexPath, 'utf8');
      index = JSON.parse(indexContent);
    } catch (e) {
      // Index doesn't exist yet
    }

    const identityMemories = [];
    for (const [key, metadata] of Object.entries(index)) {
      if (metadata.category === MEMORY_CATEGORIES.IDENTITY || metadata.importance >= 8) {
        const memory = await this.loadMemory(key);
        if (memory) {
          identityMemories.push(memory);
        }
      }
    }

    return identityMemories;
  }

  async showMemoryProfile() {
    const indexPath = '/home/jcbeasley/.openclaw/workspace/memory/_index.json';
    let index = {};
    try {
      const fs = require('fs').promises;
      const indexContent = await fs.readFile(indexPath, 'utf8');
      index = JSON.parse(indexContent);
    } catch (e) {
      // Index doesn't exist yet
    }

    const profile = {
      total: Object.keys(index).length,
      byCategory: {},
      byImportance: {},
      recent: []
    };

    // Categorize memories
    for (const [key, metadata] of Object.entries(index)) {
      // By category
      profile.byCategory[metadata.category] = (profile.byCategory[metadata.category] || 0) + 1;
      
      // By importance
      const importanceLevel = Math.floor(metadata.importance / 2) * 2; // Group by 2s
      profile.byImportance[importanceLevel] = (profile.byImportance[importanceLevel] || 0) + 1;
      
      // Recent memories (last 5)
      if (profile.recent.length < 5) {
        profile.recent.push({ key, ...metadata });
      }
    }

    return profile;
  }

  async forgetMemoriesWithTag(tag) {
    const indexPath = '/home/jcbeasley/.openclaw/workspace/memory/_index.json';
    let index = {};
    try {
      const fs = require('fs').promises;
      const indexContent = await fs.readFile(indexPath, 'utf8');
      index = JSON.parse(indexContent);
    } catch (e) {
      // Index doesn't exist yet
    }

    const deletedKeys = [];
    for (const [key, metadata] of Object.entries(index)) {
      if (metadata.tags && metadata.tags.includes(tag)) {
        await this.deleteMemory(key);
        delete index[key];
        deletedKeys.push(key);
      }
    }

    // Save updated index
    await this.index.writeFile(indexPath, JSON.stringify(index, null, 2));

    return `Deleted ${deletedKeys.length} memories with tag '${tag}': ${deletedKeys.join(', ')}`;
  }

  async updateMemoryByContent(content) {
    // This would search for related memories and update them
    // For now, we'll create a new memory
    return await this.createMemory(`mem:knowledge:${Date.now()}`, MEMORY_CATEGORIES.KNOWLEDGE, content, 6, ['user-updated']);
  }
}

// Export for use
module.exports = { MemoryManager, MEMORY_CATEGORIES };

// Example usage:
/*
const memoryManager = new MemoryManager();

// At conversation start
await memoryManager.conversationStart();

// Auto-capture during conversation
await memoryManager.autoCapture("My name is JC", {});

// Create specific memories
await memoryManager.createMemory('mem:identity:name', MEMORY_CATEGORIES.IDENTITY, 'JC', 10, ['name']);
await memoryManager.createMemory('mem:pref:format', MEMORY_CATEGORIES.PREFERENCES, 'concise answers', 7, ['format']);

// Load memories
const nameMemory = await memoryManager.loadMemory('mem:identity:name');
console.log(`User's name: ${nameMemory.content}`);
*/