#!/usr/bin/env python3
"""
Simple Codebase Search - Fallback Implementation
================================================

A lightweight fallback for codebase search functionality that doesn't
require heavy dependencies like memvid or complex neural networks.

This ensures MCP functions work even when optional dependencies fail.
"""

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

class SimpleCodebaseSearch:
    """Lightweight codebase search without heavy dependencies."""
    
    def __init__(self, project_root: Optional[str] = None):
        if project_root:
            self.project_root = Path(project_root)
        else:
            # Default to the python-memory directory
            self.project_root = Path(__file__).parent.parent
        self.supported_extensions = {
            '.py', '.js', '.ts', '.tsx', '.jsx', '.java', '.cpp', '.c', '.h',
            '.cs', '.php', '.rb', '.go', '.rs', '.swift', '.kt', '.scala',
            '.html', '.css', '.scss', '.sass', '.md', '.txt', '.yaml', '.yml',
            '.json', '.xml', '.sql', '.sh', '.bat', '.ps1'
        }
    
    def search_code(self, query: str, limit: int = 10) -> List[Dict[str, Any]]:
        """Search for code containing the query string."""
        try:
            results = []
            query_lower = query.lower()
            
            # Search through files
            for file_path in self._get_searchable_files():
                try:
                    with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                        content = f.read()
                        content_lower = content.lower()
                        
                        if query_lower in content_lower:
                            # Find relevant lines
                            lines = content.split('\n')
                            relevant_lines = []
                            
                            for line_num, line in enumerate(lines, 1):
                                if query_lower in line.lower():
                                    relevant_lines.append({
                                        'line_number': line_num,
                                        'content': line.strip(),
                                        'context': self._get_context(lines, line_num - 1)
                                    })
                                    
                                    if len(relevant_lines) >= 3:  # Limit per file
                                        break
                            
                            if relevant_lines:
                                results.append({
                                    'file_path': str(file_path.relative_to(self.project_root)),
                                    'file_type': file_path.suffix,
                                    'matches': relevant_lines,
                                    'relevance_score': len(relevant_lines) / len(lines) * 100
                                })
                                
                                if len(results) >= limit:
                                    break
                                    
                except (UnicodeDecodeError, PermissionError, OSError):
                    continue  # Skip problematic files
                    
            return sorted(results, key=lambda x: x['relevance_score'], reverse=True)
            
        except Exception as e:
            return [{'error': f'Search failed: {str(e)}'}]
    
    def explain_code(self, target: str) -> Dict[str, Any]:
        """Provide basic code explanation."""
        try:
            target_path = self.project_root / target
            
            if not target_path.exists():
                return {'error': f'File not found: {target}'}
            
            if target_path.is_dir():
                return self._explain_directory(target_path)
            else:
                return self._explain_file(target_path)
                
        except Exception as e:
            return {'error': f'Explanation failed: {str(e)}'}
    
    def _get_searchable_files(self) -> List[Path]:
        """Get list of searchable files in the project."""
        files = []
        
        for root, dirs, filenames in os.walk(self.project_root):
            # Skip common non-code directories
            dirs[:] = [d for d in dirs if not d.startswith('.') and d not in {
                'node_modules', 'venv', '__pycache__', 'build', 'dist', 'target'
            }]
            
            for filename in filenames:
                file_path = Path(root) / filename
                if file_path.suffix in self.supported_extensions:
                    files.append(file_path)
                    
        return files[:1000]  # Limit to prevent overwhelming
    
    def _get_context(self, lines: List[str], line_index: int, context_size: int = 2) -> List[str]:
        """Get context lines around a match."""
        start = max(0, line_index - context_size)
        end = min(len(lines), line_index + context_size + 1)
        return lines[start:end]
    
    def _explain_file(self, file_path: Path) -> Dict[str, Any]:
        """Explain a single file."""
        try:
            with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                content = f.read()
                
            explanation = {
                'file_path': str(file_path),
                'file_type': file_path.suffix,
                'size_bytes': len(content),
                'line_count': content.count('\n') + 1,
                'summary': f'A {file_path.suffix} file with {content.count(chr(10)) + 1} lines'
            }
            
            # Add language-specific analysis
            if file_path.suffix == '.py':
                explanation.update(self._analyze_python_file(content))
            elif file_path.suffix in {'.js', '.ts'}:
                explanation.update(self._analyze_javascript_file(content))
                
            return explanation
            
        except Exception as e:
            return {'error': f'Could not explain file: {str(e)}'}
    
    def _explain_directory(self, dir_path: Path) -> Dict[str, Any]:
        """Explain a directory structure."""
        try:
            files = list(dir_path.rglob('*'))
            file_types = {}
            
            for file_path in files:
                if file_path.is_file():
                    ext = file_path.suffix or 'no_extension'
                    file_types[ext] = file_types.get(ext, 0) + 1
            
            return {
                'directory_path': str(dir_path),
                'total_files': len([f for f in files if f.is_file()]),
                'total_directories': len([f for f in files if f.is_dir()]),
                'file_types': file_types,
                'summary': f'Directory containing {len(files)} items'
            }
            
        except Exception as e:
            return {'error': f'Could not explain directory: {str(e)}'}
    
    def _analyze_python_file(self, content: str) -> Dict[str, Any]:
        """Basic Python file analysis."""
        analysis = {}
        
        # Count functions and classes
        function_pattern = re.compile(r'^\s*def\s+(\w+)', re.MULTILINE)
        class_pattern = re.compile(r'^\s*class\s+(\w+)', re.MULTILINE)
        import_pattern = re.compile(r'^\s*(?:from\s+\S+\s+)?import\s+', re.MULTILINE)
        
        functions = function_pattern.findall(content)
        classes = class_pattern.findall(content)
        imports = import_pattern.findall(content)
        
        analysis.update({
            'language': 'Python',
            'functions': len(functions),
            'classes': len(classes),
            'imports': len(imports),
            'function_names': functions[:10],  # First 10 function names
            'class_names': classes[:10]       # First 10 class names
        })
        
        return analysis
    
    def _analyze_javascript_file(self, content: str) -> Dict[str, Any]:
        """Basic JavaScript/TypeScript file analysis."""
        analysis = {}
        
        # Count functions and exports
        function_pattern = re.compile(r'function\s+(\w+)|const\s+(\w+)\s*=.*=>', re.MULTILINE)
        export_pattern = re.compile(r'export\s+', re.MULTILINE)
        import_pattern = re.compile(r'import\s+.*from', re.MULTILINE)
        
        functions = function_pattern.findall(content)
        exports = export_pattern.findall(content)
        imports = import_pattern.findall(content)
        
        analysis.update({
            'language': 'JavaScript/TypeScript',
            'functions': len(functions),
            'exports': len(exports),
            'imports': len(imports)
        })
        
        return analysis

# Singleton instance
_simple_search_instance = None

def get_simple_codebase_search(project_root: Optional[str] = None) -> SimpleCodebaseSearch:
    """Get or create a simple codebase search instance."""
    global _simple_search_instance
    if _simple_search_instance is None:
        _simple_search_instance = SimpleCodebaseSearch(project_root)
    return _simple_search_instance