#!/usr/bin/env python3
"""
Fenrir Cache Cleanup Tool

Removes Python cache files and directories from the repository.
These files should never be committed and can cause issues.

Usage:
    python3 tools/cleanup_cache.py                    # Show what would be removed
    python3 tools/cleanup_cache.py --remove          # Actually remove cache files
    python3 tools/cleanup_cache.py --check           # Exit with error if cache files found
"""

import os
import sys
import argparse
import shutil
from pathlib import Path


class CacheCleanup:
    def __init__(self, verbose=True):
        self.verbose = verbose
        self.cache_dirs = []
        self.cache_files = []
        
    def log(self, message, level="INFO"):
        """Log a message with appropriate formatting."""
        if not self.verbose and level == "INFO":
            return
            
        colors = {
            "INFO": "\033[0;36m",     # Cyan
            "SUCCESS": "\033[0;32m",  # Green
            "WARNING": "\033[1;33m",  # Yellow
            "ERROR": "\033[0;31m",    # Red
            "HEADER": "\033[1;34m",   # Bold Blue
        }
        
        reset = "\033[0m"
        color = colors.get(level, "")
        
        if level == "HEADER":
            print(f"\n{color}{'='*60}")
            print(f"{message}")
            print(f"{'='*60}{reset}")
        else:
            symbol = {
                "SUCCESS": "✓",
                "ERROR": "✗", 
                "WARNING": "⚠",
                "INFO": "•"
            }.get(level, "•")
            
            print(f"{color}{symbol} {message}{reset}")
    
    def find_cache_files(self, directory):
        """Find all Python cache files and directories."""
        directory = Path(directory)
        
        for root, dirs, files in os.walk(directory):
            root_path = Path(root)
            
            # Skip .git directory entirely
            if '.git' in root_path.parts:
                continue
            
            # Find __pycache__ directories
            if '__pycache__' in dirs:
                cache_dir = root_path / '__pycache__'
                self.cache_dirs.append(cache_dir)
                # Don't traverse into __pycache__ directories
                dirs.remove('__pycache__')
            
            # Find .pyc files outside of __pycache__
            for file in files:
                if file.endswith('.pyc'):
                    cache_file = root_path / file
                    self.cache_files.append(cache_file)
    
    def show_findings(self):
        """Display what cache files were found."""
        total_items = len(self.cache_dirs) + len(self.cache_files)
        
        if total_items == 0:
            self.log("No Python cache files found", "SUCCESS")
            return True
        
        self.log(f"Found {total_items} cache items:", "WARNING")
        
        if self.cache_dirs:
            self.log(f"\n__pycache__ directories ({len(self.cache_dirs)}):", "WARNING")
            for cache_dir in sorted(self.cache_dirs):
                # Show size of directory
                size = self.get_directory_size(cache_dir)
                self.log(f"  {cache_dir} ({size} files)", "WARNING")
        
        if self.cache_files:
            self.log(f"\nLoose .pyc files ({len(self.cache_files)}):", "WARNING")
            for cache_file in sorted(self.cache_files):
                # Show file size
                try:
                    size = cache_file.stat().st_size
                    size_str = self.format_size(size)
                    self.log(f"  {cache_file} ({size_str})", "WARNING")
                except OSError:
                    self.log(f"  {cache_file} (size unknown)", "WARNING")
        
        return False
    
    def get_directory_size(self, directory):
        """Get the number of files in a directory."""
        try:
            return len(list(directory.rglob('*')))
        except OSError:
            return 0
    
    def format_size(self, size_bytes):
        """Format file size in human-readable format."""
        if size_bytes < 1024:
            return f"{size_bytes} B"
        elif size_bytes < 1024 * 1024:
            return f"{size_bytes // 1024} KB"
        else:
            return f"{size_bytes // (1024 * 1024)} MB"
    
    def remove_cache_files(self):
        """Actually remove the cache files and directories."""
        removed_count = 0
        errors = []
        
        # Remove __pycache__ directories
        for cache_dir in self.cache_dirs:
            try:
                if cache_dir.exists():
                    shutil.rmtree(cache_dir)
                    self.log(f"Removed directory: {cache_dir}", "SUCCESS")
                    removed_count += 1
            except OSError as e:
                error_msg = f"Failed to remove {cache_dir}: {e}"
                errors.append(error_msg)
                self.log(error_msg, "ERROR")
        
        # Remove .pyc files
        for cache_file in self.cache_files:
            try:
                if cache_file.exists():
                    cache_file.unlink()
                    self.log(f"Removed file: {cache_file}", "SUCCESS")
                    removed_count += 1
            except OSError as e:
                error_msg = f"Failed to remove {cache_file}: {e}"
                errors.append(error_msg)
                self.log(error_msg, "ERROR")
        
        if errors:
            self.log(f"Encountered {len(errors)} errors during cleanup", "ERROR")
            return False
        else:
            self.log(f"Successfully removed {removed_count} cache items", "SUCCESS")
            return True
    
    def check_gitignore(self):
        """Check if .gitignore properly excludes cache files."""
        gitignore_path = Path('.gitignore')
        if not gitignore_path.exists():
            self.log("Warning: No .gitignore file found", "WARNING")
            return False
        
        try:
            with open(gitignore_path, 'r') as f:
                content = f.read()
            
            has_pycache = '__pycache__' in content or '__pycache__/' in content
            has_pyc = '*.pyc' in content
            
            if has_pycache and has_pyc:
                self.log("✓ .gitignore properly excludes Python cache files", "SUCCESS")
                return True
            else:
                missing = []
                if not has_pycache:
                    missing.append("__pycache__/")
                if not has_pyc:
                    missing.append("*.pyc")
                
                self.log(f"Warning: .gitignore missing: {', '.join(missing)}", "WARNING")
                return False
                
        except OSError as e:
            self.log(f"Could not read .gitignore: {e}", "ERROR")
            return False
    
    def suggest_gitignore_additions(self):
        """Suggest additions to .gitignore."""
        self.log("\nRecommended .gitignore entries for Python:", "INFO")
        print("""
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
""")


def main():
    parser = argparse.ArgumentParser(description='Clean Python cache files from Fenrir repository')
    parser.add_argument('--remove', action='store_true',
                       help='Actually remove cache files (default is dry-run)')
    parser.add_argument('--check', action='store_true',
                       help='Exit with non-zero code if cache files found')
    parser.add_argument('--quiet', action='store_true',
                       help='Reduce output verbosity')
    parser.add_argument('--directory', default='.',
                       help='Directory to scan (default: current directory)')
    
    args = parser.parse_args()
    
    # Ensure we're in the project root
    if not Path("src/fenrirscreenreader").exists():
        print("Error: Must be run from Fenrir project root directory")
        sys.exit(1)
    
    cleanup = CacheCleanup(verbose=not args.quiet)
    
    cleanup.log("FENRIR CACHE CLEANUP", "HEADER")
    cleanup.log(f"Scanning directory: {Path(args.directory).absolute()}")
    
    # Find cache files
    cleanup.find_cache_files(args.directory)
    
    # Show what we found
    no_cache_found = cleanup.show_findings()
    
    if no_cache_found:
        # Check .gitignore anyway
        cleanup.check_gitignore()
        cleanup.log("\n✅ Repository is clean of Python cache files", "SUCCESS")
        sys.exit(0)
    
    # Check .gitignore
    gitignore_ok = cleanup.check_gitignore()
    if not gitignore_ok:
        cleanup.suggest_gitignore_additions()
    
    # Handle different modes
    if args.remove:
        cleanup.log("\n🧹 REMOVING CACHE FILES", "HEADER")
        success = cleanup.remove_cache_files()
        if success:
            cleanup.log("\n✅ Cache cleanup completed successfully", "SUCCESS")
            sys.exit(0)
        else:
            cleanup.log("\n❌ Cache cleanup completed with errors", "ERROR")
            sys.exit(1)
    
    elif args.check:
        cleanup.log("\n❌ Cache files found - validation failed", "ERROR")
        cleanup.log("Run with --remove to clean up cache files", "INFO")
        sys.exit(1)
    
    else:
        # Dry run mode
        cleanup.log("\n💡 DRY RUN MODE", "HEADER")
        cleanup.log("Add --remove to actually delete these files", "INFO")
        cleanup.log("Add --check to fail if cache files are present", "INFO")
        sys.exit(0)


if __name__ == '__main__':
    main()
