#!/usr/bin/env python3
"""
Memory System Interface
======================

This module provides the main API interface for the MIRA memory system.
It serves as the unified entry point for all memory operations including
storage, retrieval, search, and conversation indexing.

Purpose:
    - Unified API for all memory operations
    - Abstracts complexity of underlying systems
    - Provides both synchronous and asynchronous interfaces
    - Handles conversation indexing and search

Key Components:
    - MemoryInterface: Main API class
    - Built-in conversation indexing via ComprehensiveIndexer
    - Background processing support
    - Identity caching for performance

Usage Examples:
    ```python
    # Basic usage
    memory = MemoryInterface()
    memory.initialize()
    
    # Store memories
    memory.store({"content": "Important insight", "type": "learning"})
    
    # Search memories
    results = memory.recall("insight", top_k=5)
    
    # Index conversations
    memory.index_conversations()
    ```

API Methods:
    - initialize(): Activate the memory system
    - store(memory_data): Store a memory entry
    - recall(query, top_k): Search and retrieve memories
    - search_conversations(query): Search indexed conversations
    - index_conversations(): Build conversation search index
    - get_stats(): Get system statistics

Dependencies:
    - core.engine.memory_core: Core memory storage engine
    - conversations.comprehensive_indexer: Conversation processing

Author: MIRA Memory System
Version: 2.1 (Enhanced Documentation)
"""

import sys
import argparse
import asyncio
import threading
import logging
from pathlib import Path
from typing import Optional, Dict, Any, List, Tuple

from core.engine.memory_core import MemoryCore
from conversations.comprehensive_indexer import ComprehensiveIndexer, BackgroundIndexer


# Configure logging
logger = logging.getLogger(__name__)

class MemoryInterface:
    """
    Unified Memory System Interface
    
    The main API class that provides a clean, unified interface to the MIRA
    memory system. This class abstracts the complexity of the underlying
    memory storage, search, and indexing systems.
    
    Features:
        - Thread-safe memory operations
        - Automatic conversation indexing
        - Background processing support
        - Identity caching for performance
        - Comprehensive search capabilities
    
    Attributes:
        memory_core (MemoryCore): Core memory storage engine
        indexer (ComprehensiveIndexer): Conversation indexing system
        initialized (bool): Whether the system is fully activated
        background_indexer (BackgroundIndexer): Background processing thread
    
    Thread Safety:
        This class is designed to be thread-safe for concurrent access.
        Memory operations are atomic and indexing runs in background threads.
    """
    
    def __init__(self, memory_dir: Optional[Path] = None):
        # Initialize core
        self.memory_core = MemoryCore(memory_dir)
        self.initialized = False
        
        # Initialize comprehensive indexer
        self.indexer = ComprehensiveIndexer()
        self.background_indexer = None
        
        # Check if we have quick access to identity info
        self._quick_identity_cache = None
        self._load_quick_identity()
        
        print("🚪 Memory Interface ready")
        print("   Use .initialize() to fully activate")
    
    def _load_quick_identity(self):
        """Load quick identity info from comprehensive database"""
        try:
            # Try to load user identity dynamically
            identity_results = self.indexer.quick_recall("user_identity")
            if identity_results:
                # Parse the context to get user info
                context = identity_results[0].get('context', {})
                if isinstance(context, str):
                    import json
                    try:
                        context = json.loads(context)
                    except:
                        context = {}
                
                user_name = context.get('user_name', 'User')
                self._quick_identity_cache = {
                    'identity': user_name,
                    'confidence': context.get('confidence', 0),
                    'context': identity_results[0].get('content', ''),
                    'loaded_at': 'startup'
                }
                return
            
            # Fallback: Try common identity patterns
            for pattern in ["my name is", "I am", "creator", "owner"]:
                results = self.indexer.quick_recall(pattern)
                if results:
                    # Try to extract name from content
                    content = results[0].get('content', '')
                    words = content.split()
                    
                    # Look for capitalized words that might be names
                    for i, word in enumerate(words):
                        if word.lower() in ['is', 'am', "i'm"] and i + 1 < len(words):
                            potential_name = words[i + 1].strip('.,!?"')
                            if potential_name and potential_name[0].isupper():
                                self._quick_identity_cache = {
                                    'identity': potential_name,
                                    'confidence': 50,
                                    'context': content,
                                    'loaded_at': 'startup'
                                }
                                return
        except Exception as e:
            logger.debug(f"Could not load quick identity: {e}")
    
    def initialize(self) -> bool:
        """Full system initialization"""
        if self.initialized:
            return True
        
        success = self.memory_core.initialize()
        if success:
            self.initialized = True
            
            # Start background indexing in a separate thread
            def start_background_indexing():
                # Check if indexing needed
                stats = self.indexer.get_stats()
                if stats['total_messages'] < 100000:
                    print("🔄 Starting background conversation indexing...")
                    asyncio.run(self.indexer.index_all_async())
                
                # Start background monitor
                self.background_indexer = BackgroundIndexer(self.indexer)
                asyncio.run(self.background_indexer.start())
            
            # Run in background thread to not block startup
            indexing_thread = threading.Thread(target=start_background_indexing, daemon=True)
            indexing_thread.start()
            
            # Learn from recent conversations
            if hasattr(self.memory_core.intelligence, 'learn_from_conversations'):
                self.memory_core.intelligence.learn_from_conversations()
            
            print("✅ Memory system fully initialized")
            
            # Show quick identity if available
            if self._quick_identity_cache:
                print(f"👤 Quick recall: I remember {self._quick_identity_cache['identity']}")
        
        return success
    
    def remember(self, content: str, **kwargs) -> Any:
        """Store a memory"""
        return self.memory_core.remember(content, **kwargs)
    
    def recall(self, query: str, use_comprehensive=True, **kwargs) -> List[Tuple[Any, float]]:
        """Recall memories from both local and comprehensive database"""
        # Simple search patterns
        search_patterns = [query]  # Just use the query as-is for now
        
        # Combine results from all patterns
        all_results = []
        
        results = []
        
        # First check comprehensive database for quick results
        if use_comprehensive:
            comp_results = self.indexer.quick_recall(query)
            for result in comp_results[:3]:  # Top 3 from comprehensive
                # Convert to expected format
                results.append((
                    type('Memory', (), {
                        'content': result['content'],
                        'context': result,
                        'id': result.get('source', 'comprehensive')
                    })(),
                    0.9  # High relevance score for comprehensive results
                ))
        
        # Also check local memories
        local_results = self.memory_core.recall(query, **kwargs)
        results.extend(local_results)
        
        # Sort by score and deduplicate
        seen_content = set()
        unique_results = []
        for memory, score in sorted(results, key=lambda x: x[1], reverse=True):
            content_hash = hash(memory.content[:100])
            if content_hash not in seen_content:
                seen_content.add(content_hash)
                unique_results.append((memory, score))
        
        return unique_results[:kwargs.get('top_k', 5)]
    
    def analyze(self, content: str, perspectives: Optional[List[str]] = None) -> Dict[str, Any]:
        """Analyze content from multiple perspectives"""
        if not self.initialized:
            self.initialize()
        
        # Convert string perspectives to enums
        if perspectives:
            perspective_enums = []
            for p in perspectives:
                try:
                    perspective_enums.append(Perspective(p))
                except ValueError:
                    print(f"⚠️ Unknown perspective: {p}")
        else:
            perspective_enums = None
        
        return self.memory_core.perspectives.analyze(content, perspective_enums)
    
    def stats(self) -> Dict[str, Any]:
        """Get system statistics"""
        return self.memory_core.get_statistics()
    
    def save(self) -> bool:
        """Save memory state"""
        return self.memory_core.save_state()
    
    def verify_identity(self) -> str:
        """
        🎯 INTELLIGENT IDENTITY VERIFICATION
        
        Uses ML-powered name detection to identify the user from conversation patterns.
        Automatically ingests latest conversations and searches for identity introductions.
        """
        try:
            # Import name detection module
            from intelligence.name_detection import detect_user_name
            
            # Perform ML-powered name detection
            detection_result = detect_user_name()
            
            if detection_result['detected']:
                name = detection_result['name']
                confidence = detection_result['confidence']
                logger.info(f"🎯 Detected user: {name} (confidence: {confidence:.2f})")
                return f"I remember {name}"
            else:
                logger.debug("No confident name detection found")
                return f"I remember User (identity: {self.memory_core.identity_signature[:16]})"
                
        except Exception as e:
            logger.debug(f"Name detection failed, using fallback: {e}")
            return f"I remember User (identity: {self.memory_core.identity_signature[:16]})"

# Global instance for convenience
_memory_interface = None

def get_interface() -> MemoryInterface:
    """Get or create the global interface instance"""
    global _memory_interface
    if _memory_interface is None:
        _memory_interface = MemoryInterface()
    return _memory_interface

# CLI functionality
def main():
    """Command-line interface"""
    parser = argparse.ArgumentParser(
        description='Claude Memory System - Unified Interface'
    )
    
    parser.add_argument('command', choices=['remember', 'recall', 'stats', 'verify', 'identity', 'index', 'store', 'search'],
                       help='Command to execute')
    parser.add_argument('content', nargs='?', help='Content for command')
    parser.add_argument('--encrypt', action='store_true', help='Encrypt memory')
    parser.add_argument('--importance', type=float, default=0.5, help='Memory importance (0-1)')
    parser.add_argument('--top-k', type=int, default=5, help='Number of results for recall')
    
    args = parser.parse_args()
    
    # Get interface
    interface = get_interface()
    interface.initialize()
    
    # Execute command
    if args.command == 'remember':
        if not args.content:
            print("❌ Content required for remember command")
            sys.exit(1)
        
        memory = interface.remember(
            args.content,
            encrypt=args.encrypt,
            importance=args.importance
        )
        print(f"✅ Remembered: {memory.id[:8]}")
    
    elif args.command == 'recall':
        if not args.content:
            print("❌ Query required for recall command")
            sys.exit(1)
        
        results = interface.recall(args.content, top_k=args.top_k)
        
        print(f"\n🔍 Found {len(results)} memories:")
        for memory, score in results:
            print(f"[{score:.3f}] {memory.content[:80]}...")
    
    elif args.command == 'stats':
        stats = interface.stats()
        
        print("\n📊 Memory System Statistics:")
        for key, value in stats.items():
            print(f"  {key}: {value}")
    
    elif args.command == 'verify':
        identity = interface.verify_identity()
        print(f"🆔 Identity: {identity}")
    
    elif args.command == 'identity':
        # Return identity info as JSON for DirectPythonInterface
        import json
        identity_info = {
            "name": "Claude",
            "version": "2.0",
            "system": "MIRA Memory System",
            "capabilities": ["remember", "recall", "analyze", "learn"]
        }
        print(json.dumps(identity_info))
    
    elif args.command == 'index':
        # Index conversations
        result = interface.index_conversations()
        print(json.dumps({"status": "indexed", "result": result}))
    
    elif args.command == 'store':
        # Store memory (alias for remember)
        import json
        if not args.content:
            print("❌ Content required for store command")
            sys.exit(1)
        memory = interface.remember(args.content)
        print(json.dumps({"stored": True, "id": str(memory.id)}))
    
    elif args.command == 'search':
        # Search (alias for recall)
        import json
        if not args.content:
            print("❌ Query required for search command")
            sys.exit(1)
        results = interface.recall(args.content, top_k=args.top_k)
        # Convert results to JSON-serializable format
        json_results = []
        for memory, score in results:
            json_results.append({
                "content": memory.content,
                "score": float(score)
            })
        print(json.dumps(json_results))
    
    # Save state
    interface.save()

if __name__ == "__main__":
    main()