#!/usr/bin/env python3
"""
Fenrir Syntax Validation Tool

Validates Python syntax across the entire Fenrir codebase without writing
cache files. Designed to catch syntax errors before packaging or releases.

Usage:
    python3 tools/validate_syntax.py                    # Validate all Python files
    python3 tools/validate_syntax.py --fix             # Fix common issues automatically
    python3 tools/validate_syntax.py --check-only      # Exit with non-zero if errors found
"""

import ast
import os
import re
import sys
import argparse
import tempfile
from pathlib import Path


class SyntaxValidator:
    def __init__(self):
        self.errors = []
        self.warnings = []
        self.fixed = []

    def check_fstring_issues(self, content):
        """Check for common f-string formatting issues that cause syntax errors."""
        issues = []
        lines = content.split('\n')

        for i, line in enumerate(lines, 1):
            # Check for f-strings that appear to be broken across lines
            # Pattern: f"some text {
            if re.search(r'f"[^"]*{[^}]*$', line.strip()):
                issues.append(f"Line {i}: Potential broken multiline f-string")

        return issues

    def validate_file(self, filepath):
        """Validate syntax of a single Python file."""
        try:
            with open(filepath, 'r', encoding='utf-8') as f:
                content = f.read()

            # Check for specific f-string issues before AST parsing
            fstring_issues = self.check_fstring_issues(content)
            if fstring_issues:
                # Create a synthetic syntax error for f-string issues
                error_msg = f"F-string issues: {'; '.join(fstring_issues)}"
                self.errors.append((filepath, SyntaxError(error_msg), content))
                return False, content

            # Parse with AST (catches syntax errors)
            ast.parse(content, filename=str(filepath))
            return True, content
            
        except SyntaxError as e:
            error_msg = f"{filepath}:{e.lineno}: {e.msg}"
            self.errors.append((filepath, e, content))
            return False, content
            
        except UnicodeDecodeError as e:
            error_msg = f"{filepath}: Unicode decode error: {e}"
            self.errors.append((filepath, e, None))
            return False, None
            
        except Exception as e:
            error_msg = f"{filepath}: Unexpected error: {e}"
            self.errors.append((filepath, e, None))
            return False, None
    
    def fix_common_issues(self, filepath, content):
        """Attempt to fix common syntax issues automatically."""
        if not content:
            return False, content
            
        original_content = content
        fixed_issues = []
        
        # Fix unterminated f-strings (the main issue from the email)
        lines = content.split('\n')
        modified = False
        
        for i, line in enumerate(lines):
            # Look for f-strings that span multiple lines incorrectly
            if 'f"' in line and line.count('"') % 2 == 1:
                # Check if this looks like a broken multi-line f-string
                indent = len(line) - len(line.lstrip())
                
                # Look ahead for continuation
                j = i + 1
                while j < len(lines) and lines[j].strip():
                    next_line = lines[j]
                    next_indent = len(next_line) - len(next_line.lstrip())
                    
                    # If next line is indented more and has closing brace/quote
                    if (next_indent > indent and 
                        ('"' in next_line or '}' in next_line)):
                        
                        # Try to fix by joining lines properly
                        combined_line = line.rstrip()
                        continuation = next_line.strip()
                        
                        if continuation.startswith(('"', '}', 'str(e)', 'self.', 'fenrirVersion.')):
                            # Fix common patterns
                            if 'str(e)}' in continuation:
                                fixed_line = line.replace('f"', 'f"').rstrip() + '{' + continuation.replace('"', '') + '}'
                            elif continuation.startswith('"'):
                                fixed_line = line + continuation
                            else:
                                fixed_line = line.rstrip() + continuation
                            
                            lines[i] = fixed_line
                            lines[j] = ''  # Remove the continuation line
                            modified = True
                            fixed_issues.append(f"Line {i+1}: Fixed multi-line f-string")
                    break
                    j += 1
        
        if modified:
            content = '\n'.join(lines)
            # Clean up empty lines that were created
            content = '\n'.join(line for line in content.split('\n') if line.strip() or not line)
            
            # Verify the fix worked
            try:
                ast.parse(content, filename=str(filepath))
                self.fixed.append((filepath, fixed_issues))
                return True, content
            except SyntaxError:
                # Fix didn't work, return original
                return False, original_content
        
        return False, content
    
    def scan_directory(self, directory, fix_mode=False):
        """Scan directory for Python files and validate them."""
        python_files = []
        
        # Find all Python files
        for root, dirs, files in os.walk(directory):
            # Skip cache and build directories
            dirs[:] = [d for d in dirs if not d.startswith(('__pycache__', '.git', 'build', 'dist'))]
            
            for file in files:
                if file.endswith('.py'):
                    python_files.append(Path(root) / file)
        
        print(f"Validating {len(python_files)} Python files...")
        
        valid_count = 0
        fixed_count = 0
        
        for filepath in sorted(python_files):
            is_valid, content = self.validate_file(filepath)
            
            if is_valid:
                valid_count += 1
                print(f"✓ {filepath}")
            else:
                print(f"✗ {filepath}")
                
                if fix_mode and content:
                    # Try to fix the file
                    was_fixed, fixed_content = self.fix_common_issues(filepath, content)
                    if was_fixed:
                        # Write the fixed content back
                        with open(filepath, 'w', encoding='utf-8') as f:
                            f.write(fixed_content)
                        print(f"  → Fixed automatically")
                        fixed_count += 1
                        
                        # Re-validate
                        is_valid_now, _ = self.validate_file(filepath)
                        if is_valid_now:
                            valid_count += 1
        
        return valid_count, len(python_files), fixed_count
    
    def print_summary(self, valid_count, total_count, fixed_count=0):
        """Print validation summary."""
        print(f"\n{'='*60}")
        print(f"SYNTAX VALIDATION SUMMARY")
        print(f"{'='*60}")
        print(f"Valid files:     {valid_count}/{total_count}")
        print(f"Invalid files:   {total_count - valid_count}")
        if fixed_count > 0:
            print(f"Auto-fixed:      {fixed_count}")
        
        if self.errors:
            print(f"\nERRORS ({len(self.errors)}):")
            for filepath, error, _ in self.errors:
                if isinstance(error, SyntaxError):
                    print(f"  {filepath}:{error.lineno}: {error.msg}")
                else:
                    print(f"  {filepath}: {error}")
        
        if self.fixed:
            print(f"\nAUTO-FIXES APPLIED ({len(self.fixed)}):")
            for filepath, fixes in self.fixed:
                print(f"  {filepath}:")
                for fix in fixes:
                    print(f"    - {fix}")
        
        success_rate = (valid_count / total_count) * 100 if total_count > 0 else 0
        print(f"\nSuccess rate: {success_rate:.1f}%")
        
        return len(self.errors) == 0


def main():
    parser = argparse.ArgumentParser(description='Validate Python syntax in Fenrir codebase')
    parser.add_argument('--fix', action='store_true', 
                       help='Attempt to fix common syntax issues automatically')
    parser.add_argument('--check-only', action='store_true',
                       help='Exit with non-zero code if syntax errors found')
    parser.add_argument('--directory', default='src/fenrirscreenreader',
                       help='Directory to scan (default: src/fenrirscreenreader)')
    
    args = parser.parse_args()
    
    # Find project root
    script_dir = Path(__file__).parent
    project_root = script_dir.parent
    target_dir = project_root / args.directory
    
    if not target_dir.exists():
        print(f"Error: Directory {target_dir} does not exist")
        sys.exit(1)
    
    print(f"Fenrir Syntax Validator")
    print(f"Target directory: {target_dir}")
    print(f"Fix mode: {'ON' if args.fix else 'OFF'}")
    print()
    
    validator = SyntaxValidator()
    valid_count, total_count, fixed_count = validator.scan_directory(target_dir, fix_mode=args.fix)
    
    all_valid = validator.print_summary(valid_count, total_count, fixed_count)
    
    if args.check_only and not all_valid:
        print(f"\nValidation failed: {total_count - valid_count} files have syntax errors")
        sys.exit(1)
    elif not all_valid:
        print(f"\nWarning: {total_count - valid_count} files have syntax errors")
        if not args.fix:
            print("Run with --fix to attempt automatic fixes")
        sys.exit(1)
    else:
        print(f"\n✓ All {total_count} files have valid syntax")
        sys.exit(0)


if __name__ == '__main__':
    main()
