#!/usr/bin/env python3
"""
Migration script to update pygeai.gam imports to pygeai_gam.

This script helps users migrate their code from the deprecated pygeai.gam
module to the new standalone pygeai-gam package.
"""
import argparse
import os
import re
import sys
import shutil
from pathlib import Path
from typing import List, Tuple, Optional
from datetime import datetime


class Colors:
    """ANSI color codes for terminal output."""
    RESET = "\033[0m"
    RED = "\033[91m"
    GREEN = "\033[92m"
    YELLOW = "\033[93m"
    BLUE = "\033[94m"
    MAGENTA = "\033[95m"
    CYAN = "\033[96m"
    BOLD = "\033[1m"
    
    @classmethod
    def disable(cls):
        """Disable colors for non-TTY terminals."""
        cls.RESET = ""
        cls.RED = ""
        cls.GREEN = ""
        cls.YELLOW = ""
        cls.BLUE = ""
        cls.MAGENTA = ""
        cls.CYAN = ""
        cls.BOLD = ""


# Disable colors if not running in a TTY
if not sys.stdout.isatty():
    Colors.disable()


# Import patterns to replace
IMPORT_PATTERNS = [
    # from pygeai.gam.X import Y
    (
        re.compile(r'\bfrom\s+pygeai\.gam\.([\w.]+)\s+import\s+'),
        r'from pygeai_gam.\1 import '
    ),
    # import pygeai.gam.X
    (
        re.compile(r'\bimport\s+pygeai\.gam\.([\w.]+)'),
        r'import pygeai_gam.\1'
    ),
    # from pygeai.gam import X
    (
        re.compile(r'\bfrom\s+pygeai\.gam\s+import\s+'),
        r'from pygeai_gam import '
    ),
    # import pygeai.gam
    (
        re.compile(r'\bimport\s+pygeai\.gam\b'),
        r'import pygeai_gam'
    ),
]


def find_python_files(directory: Path) -> List[Path]:
    """
    Recursively find all Python files in a directory.
    
    Args:
        directory: Root directory to search
        
    Returns:
        List of Path objects for Python files
    """
    python_files = []
    for root, dirs, files in os.walk(directory):
        # Skip common non-source directories
        dirs[:] = [d for d in dirs if d not in {'.git', '.venv', 'venv', '__pycache__', 
                                                 '.pytest_cache', '.mypy_cache', 'node_modules',
                                                 'build', 'dist', '.tox', '.eggs'}]
        
        for file in files:
            if file.endswith('.py'):
                python_files.append(Path(root) / file)
    
    return python_files


def check_file_for_imports(file_path: Path) -> bool:
    """
    Check if a file contains pygeai.gam imports.
    
    Args:
        file_path: Path to the file to check
        
    Returns:
        True if file contains pygeai.gam imports
    """
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
            return 'pygeai.gam' in content
    except (UnicodeDecodeError, IOError):
        return False


def migrate_file(file_path: Path, dry_run: bool = False, backup: bool = True) -> Tuple[bool, int]:
    """
    Migrate a single file from pygeai.gam to pygeai_gam.
    
    Args:
        file_path: Path to the file to migrate
        dry_run: If True, don't actually modify the file
        backup: If True, create a backup before modifying
        
    Returns:
        Tuple of (was_modified, number_of_replacements)
    """
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            original_content = f.read()
    except (UnicodeDecodeError, IOError) as e:
        print(f"{Colors.RED}Error reading {file_path}: {e}{Colors.RESET}")
        return False, 0
    
    new_content = original_content
    total_replacements = 0
    
    # Apply all import patterns
    for pattern, replacement in IMPORT_PATTERNS:
        new_content, num_replacements = pattern.subn(replacement, new_content)
        total_replacements += num_replacements
    
    # If nothing changed, return early
    if new_content == original_content:
        return False, 0
    
    if not dry_run:
        # Create backup if requested
        if backup:
            backup_path = file_path.with_suffix('.py.bak')
            shutil.copy2(file_path, backup_path)
        
        # Write the modified content
        try:
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(new_content)
        except IOError as e:
            print(f"{Colors.RED}Error writing {file_path}: {e}{Colors.RESET}")
            return False, 0
    
    return True, total_replacements


def show_diff(file_path: Path, dry_run: bool = False):
    """
    Show what changes would be made to a file.
    
    Args:
        file_path: Path to the file
        dry_run: If True, read from original file; else read from backup
    """
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            original = f.read()
    except (UnicodeDecodeError, IOError):
        return
    
    new_content = original
    for pattern, replacement in IMPORT_PATTERNS:
        new_content = pattern.sub(replacement, new_content)
    
    if new_content == original:
        return
    
    # Show line-by-line diff
    original_lines = original.splitlines()
    new_lines = new_content.splitlines()
    
    print(f"\n{Colors.CYAN}{Colors.BOLD}Changes in {file_path}:{Colors.RESET}")
    
    for i, (old_line, new_line) in enumerate(zip(original_lines, new_lines), 1):
        if old_line != new_line:
            print(f"{Colors.RED}- {old_line}{Colors.RESET}")
            print(f"{Colors.GREEN}+ {new_line}{Colors.RESET}")


def main():
    """Main entry point for the migration script."""
    parser = argparse.ArgumentParser(
        description="Migrate code from pygeai.gam to pygeai_gam",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  # Dry run to preview changes
  migrate-pygeai-gam /path/to/project --dry-run
  
  # Migrate with backups
  migrate-pygeai-gam /path/to/project --backup
  
  # Migrate without backups and show verbose output
  migrate-pygeai-gam /path/to/project --no-backup --verbose
  
  # Migrate current directory
  migrate-pygeai-gam .

For more information, see:
  https://docs.globant.ai/pygeai/pygeai_gam_migration.html
        """
    )
    
    parser.add_argument(
        'directory',
        type=str,
        help='Directory containing Python files to migrate'
    )
    
    parser.add_argument(
        '--dry-run',
        action='store_true',
        help='Show what would be changed without modifying files'
    )
    
    parser.add_argument(
        '--backup',
        action='store_true',
        default=True,
        help='Create backup files (.py.bak) before modifying (default: True)'
    )
    
    parser.add_argument(
        '--no-backup',
        action='store_true',
        help='Do not create backup files'
    )
    
    parser.add_argument(
        '--verbose',
        '-v',
        action='store_true',
        help='Show detailed information about changes'
    )
    
    args = parser.parse_args()
    
    # Handle backup flags
    create_backup = args.backup and not args.no_backup
    
    # Validate directory
    directory = Path(args.directory).resolve()
    if not directory.exists():
        print(f"{Colors.RED}Error: Directory '{directory}' does not exist{Colors.RESET}")
        return 1
    
    if not directory.is_dir():
        print(f"{Colors.RED}Error: '{directory}' is not a directory{Colors.RESET}")
        return 1
    
    # Print header
    print(f"{Colors.BOLD}{Colors.BLUE}╔════════════════════════════════════════════════════════════╗{Colors.RESET}")
    print(f"{Colors.BOLD}{Colors.BLUE}║  pygeai.gam → pygeai_gam Migration Tool                 ║{Colors.RESET}")
    print(f"{Colors.BOLD}{Colors.BLUE}╚════════════════════════════════════════════════════════════╝{Colors.RESET}")
    print()
    print(f"Scanning directory: {Colors.CYAN}{directory}{Colors.RESET}")
    
    if args.dry_run:
        print(f"{Colors.YELLOW}Mode: DRY RUN (no files will be modified){Colors.RESET}")
    else:
        print(f"{Colors.GREEN}Mode: ACTIVE (files will be modified){Colors.RESET}")
        if create_backup:
            print(f"{Colors.YELLOW}Backups: Enabled (.py.bak files will be created){Colors.RESET}")
        else:
            print(f"{Colors.RED}Backups: Disabled (no backup files will be created){Colors.RESET}")
    
    print()
    
    # Find all Python files
    print(f"{Colors.BOLD}Finding Python files...{Colors.RESET}")
    python_files = find_python_files(directory)
    print(f"Found {Colors.BOLD}{len(python_files)}{Colors.RESET} Python files")
    print()
    
    # Check which files need migration
    print(f"{Colors.BOLD}Checking for pygeai.gam imports...{Colors.RESET}")
    files_to_migrate = [f for f in python_files if check_file_for_imports(f)]
    
    if not files_to_migrate:
        print(f"{Colors.GREEN}✓ No files need migration!{Colors.RESET}")
        print(f"All files are already using pygeai_gam or don't import from proxy module.")
        return 0
    
    print(f"Found {Colors.BOLD}{Colors.YELLOW}{len(files_to_migrate)}{Colors.RESET} files with pygeai.gam imports")
    print()
    
    # Migrate files
    modified_files = []
    total_replacements = 0
    
    print(f"{Colors.BOLD}Migrating files...{Colors.RESET}")
    for file_path in files_to_migrate:
        was_modified, num_replacements = migrate_file(file_path, args.dry_run, create_backup)
        
        if was_modified:
            modified_files.append(file_path)
            total_replacements += num_replacements
            
            rel_path = file_path.relative_to(directory)
            status = f"{Colors.YELLOW}[DRY RUN]{Colors.RESET}" if args.dry_run else f"{Colors.GREEN}[MODIFIED]{Colors.RESET}"
            print(f"{status} {rel_path} ({num_replacements} replacements)")
            
            if args.verbose:
                show_diff(file_path, args.dry_run)
    
    # Print summary
    print()
    print(f"{Colors.BOLD}{Colors.BLUE}╔════════════════════════════════════════════════════════════╗{Colors.RESET}")
    print(f"{Colors.BOLD}{Colors.BLUE}║  Migration Summary                                         ║{Colors.RESET}")
    print(f"{Colors.BOLD}{Colors.BLUE}╚════════════════════════════════════════════════════════════╝{Colors.RESET}")
    print()
    print(f"Files scanned:       {Colors.BOLD}{len(python_files)}{Colors.RESET}")
    print(f"Files with imports:  {Colors.BOLD}{Colors.YELLOW}{len(files_to_migrate)}{Colors.RESET}")
    print(f"Files modified:      {Colors.BOLD}{Colors.GREEN}{len(modified_files)}{Colors.RESET}")
    print(f"Total replacements:  {Colors.BOLD}{total_replacements}{Colors.RESET}")
    
    if args.dry_run:
        print()
        print(f"{Colors.YELLOW}This was a dry run. No files were modified.{Colors.RESET}")
        print(f"Run without --dry-run to apply changes.")
    else:
        print()
        print(f"{Colors.GREEN}✓ Migration complete!{Colors.RESET}")
        
        if create_backup:
            print()
            print(f"{Colors.CYAN}Backup files (.py.bak) have been created.{Colors.RESET}")
            print(f"You can remove them after verifying the migration:")
            print(f"  find {directory} -name '*.py.bak' -delete")
    
    print()
    print(f"{Colors.BOLD}Next steps:{Colors.RESET}")
    print(f"  1. Install pygeai-gam: {Colors.CYAN}pip install pygeai-gam{Colors.RESET}")
    print(f"  2. Test your application")
    print(f"  3. Remove backup files (if created)")
    print()
    print(f"For more information, see:")
    print(f"  {Colors.CYAN}https://docs.globant.ai/pygeai/pygeai_gam_migration.html{Colors.RESET}")
    print()
    
    return 0


if __name__ == '__main__':
    sys.exit(main())
