"""
AbuLang Cache System - .abuc file for command library and caching
Similar to __pycache__ but stores all executed commands as reusable library
"""

import json
import os
from pathlib import Path
from datetime import datetime
from typing import Dict, List, Any, Optional


class AbuCache:
    """Manages .abuc cache files for command storage and reuse"""
    
    CACHE_DIR = ".abuc"
    CACHE_FILE = "commands.json"
    METADATA_FILE = "metadata.json"
    
    def __init__(self, project_root: Optional[str] = None):
        """Initialize cache system"""
        self.project_root = Path(project_root or ".")
        self.cache_path = self.project_root / self.CACHE_DIR
        self.commands_file = self.cache_path / self.CACHE_FILE
        self.metadata_file = self.cache_path / self.METADATA_FILE
        
        self.commands: Dict[str, Any] = {}
        self.metadata = {
            "created": None,
            "last_updated": None,
            "total_commands": 0,
            "version": "1.0"
        }
        
        self._ensure_cache_dir()
        self._load_cache()
    
    def _ensure_cache_dir(self):
        """Create .abuc directory if it doesn't exist"""
        self.cache_path.mkdir(exist_ok=True)
    
    def _load_cache(self):
        """Load existing cache from disk"""
        if self.commands_file.exists():
            try:
                with open(self.commands_file, 'r') as f:
                    self.commands = json.load(f)
            except (json.JSONDecodeError, IOError):
                self.commands = {}
        
        if self.metadata_file.exists():
            try:
                with open(self.metadata_file, 'r') as f:
                    self.metadata = json.load(f)
            except (json.JSONDecodeError, IOError):
                self.metadata = self._default_metadata()
        else:
            self.metadata = self._default_metadata()
    
    def _default_metadata(self) -> Dict:
        """Get default metadata"""
        return {
            "created": datetime.now().isoformat(),
            "last_updated": datetime.now().isoformat(),
            "total_commands": 0,
            "version": "1.0"
        }
    
    def _save_cache(self):
        """Save cache to disk"""
        self.metadata["last_updated"] = datetime.now().isoformat()
        self.metadata["total_commands"] = len(self.commands)
        
        with open(self.commands_file, 'w') as f:
            json.dump(self.commands, f, indent=2)
        
        with open(self.metadata_file, 'w') as f:
            json.dump(self.metadata, f, indent=2)
    
    def cache_command(self, command_name: str, code: str, result: Any = None, 
                     execution_time: float = 0.0, tags: List[str] = None):
        """Cache a command for reuse"""
        if tags is None:
            tags = []
        
        self.commands[command_name] = {
            "code": code,
            "result": result,
            "execution_time": execution_time,
            "tags": tags,
            "cached_at": datetime.now().isoformat(),
            "usage_count": 0
        }
        
        self._save_cache()
    
    def get_command(self, command_name: str) -> Optional[Dict]:
        """Retrieve cached command"""
        if command_name in self.commands:
            cmd = self.commands[command_name]
            cmd["usage_count"] = cmd.get("usage_count", 0) + 1
            self._save_cache()
            return cmd
        return None
    
    def has_command(self, command_name: str) -> bool:
        """Check if command is cached"""
        return command_name in self.commands
    
    def list_commands(self, tag: Optional[str] = None) -> List[str]:
        """List all cached commands, optionally filtered by tag"""
        if tag:
            return [name for name, cmd in self.commands.items() 
                   if tag in cmd.get("tags", [])]
        return list(self.commands.keys())
    
    def search_commands(self, query: str) -> List[str]:
        """Search commands by name or tag"""
        query = query.lower()
        results = []
        
        for name, cmd in self.commands.items():
            if query in name.lower():
                results.append(name)
            elif any(query in tag.lower() for tag in cmd.get("tags", [])):
                results.append(name)
        
        return results
    
    def delete_command(self, command_name: str) -> bool:
        """Delete cached command"""
        if command_name in self.commands:
            del self.commands[command_name]
            self._save_cache()
            return True
        return False
    
    def clear_cache(self):
        """Clear all cached commands"""
        self.commands.clear()
        self.metadata = self._default_metadata()
        self._save_cache()
    
    def get_stats(self) -> Dict:
        """Get cache statistics"""
        total_time = sum(cmd.get("execution_time", 0) for cmd in self.commands.values())
        total_uses = sum(cmd.get("usage_count", 0) for cmd in self.commands.values())
        
        return {
            "total_commands": len(self.commands),
            "total_execution_time": total_time,
            "total_uses": total_uses,
            "cache_size_bytes": self.commands_file.stat().st_size if self.commands_file.exists() else 0,
            "created": self.metadata.get("created"),
            "last_updated": self.metadata.get("last_updated")
        }
    
    def export_library(self, filename: str = "abulang_library.abu") -> str:
        """Export cached commands as .abu library file"""
        library_code = "# AbuLang Command Library\n"
        library_code += f"# Generated from .abuc cache\n"
        library_code += f"# Total commands: {len(self.commands)}\n\n"
        
        for name, cmd in self.commands.items():
            library_code += f"# Command: {name}\n"
            if cmd.get("tags"):
                library_code += f"# Tags: {', '.join(cmd['tags'])}\n"
            library_code += f"# Execution time: {cmd.get('execution_time', 0):.4f}s\n"
            library_code += f"# Usage count: {cmd.get('usage_count', 0)}\n"
            library_code += f"{cmd['code']}\n\n"
        
        output_path = self.project_root / filename
        with open(output_path, 'w') as f:
            f.write(library_code)
        
        return str(output_path)
    
    def import_library(self, filename: str) -> int:
        """Import commands from .abu library file"""
        lib_path = self.project_root / filename
        
        if not lib_path.exists():
            raise FileNotFoundError(f"Library file not found: {filename}")
        
        imported = 0
        with open(lib_path, 'r') as f:
            lines = f.readlines()
        
        current_command = None
        current_code = []
        
        for line in lines:
            if line.startswith("# Command:"):
                if current_command and current_code:
                    self.cache_command(current_command, '\n'.join(current_code))
                    imported += 1
                
                current_command = line.replace("# Command:", "").strip()
                current_code = []
            elif not line.startswith("#") and line.strip():
                current_code.append(line.rstrip())
        
        # Save last command
        if current_command and current_code:
            self.cache_command(current_command, '\n'.join(current_code))
            imported += 1
        
        self._save_cache()
        return imported
    
    def get_cache_info(self) -> str:
        """Get human-readable cache information"""
        stats = self.get_stats()
        
        info = "=== AbuLang Cache (.abuc) ===\n"
        info += f"Location: {self.cache_path}\n"
        info += f"Total Commands: {stats['total_commands']}\n"
        info += f"Total Uses: {stats['total_uses']}\n"
        info += f"Total Execution Time: {stats['total_execution_time']:.4f}s\n"
        info += f"Cache Size: {stats['cache_size_bytes']} bytes\n"
        info += f"Created: {stats['created']}\n"
        info += f"Last Updated: {stats['last_updated']}\n"
        
        return info


class CacheManager:
    """High-level cache management for AbuLang interpreter"""
    
    def __init__(self, project_root: Optional[str] = None):
        self.cache = AbuCache(project_root)
        self.auto_cache = True
    
    def enable_auto_cache(self):
        """Enable automatic caching of all commands"""
        self.auto_cache = True
    
    def disable_auto_cache(self):
        """Disable automatic caching"""
        self.auto_cache = False
    
    def cache_execution(self, command_name: str, code: str, result: Any = None, 
                       execution_time: float = 0.0, tags: List[str] = None):
        """Cache command execution if auto_cache is enabled"""
        if self.auto_cache:
            self.cache.cache_command(command_name, code, result, execution_time, tags)
    
    def get_cached_command(self, command_name: str) -> Optional[str]:
        """Get cached command code"""
        cmd = self.cache.get_command(command_name)
        return cmd["code"] if cmd else None
    
    def show_cache_stats(self):
        """Display cache statistics"""
        print(self.cache.get_cache_info())
    
    def show_cached_commands(self, tag: Optional[str] = None):
        """Display list of cached commands"""
        commands = self.cache.list_commands(tag)
        
        if not commands:
            print("No cached commands found")
            return
        
        print(f"Cached Commands ({len(commands)}):")
        for cmd in commands:
            info = self.cache.get_command(cmd)
            print(f"  • {cmd} (used {info['usage_count']} times)")
