"""
AbuLang Forgiving Mode - AI-Assisted Syntax Correction
Automatically fixes common syntax errors and suggests corrections
"""

import re
from difflib import get_close_matches


class ForgivingMode:
    """
    Forgiving Mode: Auto-corrects common syntax errors in AbuLang code
    """
    
    def __init__(self):
        # AbuLang keywords and commands
        self.keywords = [
            'show', 'print', 'check', 'if', 'elifi', 'elif', 'else', 'other',
            'loopf', 'for', 'while', 'scan', 'break', 'stop', 'continue', 'conti', 'skip',
            'def', 'return', 'use', 'from', 'import', 'as',
            'Create', 'store', 'into', 'pull', 'clear', 'in',
            'rerun', 'restart'
        ]
        
        self.functions = [
            'plus', 'minus', 'multi', 'divid', 'expon', 'modul',
            'strip', 'lower', 'upper', 'lengt', 'replc', 'findt', 'joinc',
            'split', 'includes', 'matches', 'ask', 'prompt', 'alert', 'confirm',
            'floor', 'ceili', 'absof', 'sumup', 'avera', 'range',
            'print_page', 'console'
        ]
        
        # Common typos and their corrections
        self.common_typos = {
            'shwo': 'show',
            'sho': 'show',
            'shpw': 'show',
            'pritn': 'print',
            'prnit': 'print',
            'chekc': 'check',
            'chek': 'check',
            'cheeck': 'check',
            'esle': 'else',
            'esli': 'elifi',
            'ellif': 'elifi',
            'retrun': 'return',
            'reutrn': 'return',
            'whiel': 'while',
            'wihle': 'while',
            'dfe': 'def',
            'fed': 'def',
            'promtp': 'prompt',
            'promt': 'prompt',
            'alret': 'alert',
            'confrm': 'confirm',
            'confrim': 'confirm',
        }
        
        # Python to AbuLang conversions
        self.python_to_abulang = {
            'elif': 'elifi',
            'print': 'show',
            'input': 'prompt',
        }
        
        self.corrections = []
        self.warnings = []
    
    def levenshtein_distance(self, s1, s2):
        """Calculate Levenshtein distance between two strings"""
        if len(s1) < len(s2):
            return self.levenshtein_distance(s2, s1)
        
        if len(s2) == 0:
            return len(s1)
        
        previous_row = range(len(s2) + 1)
        for i, c1 in enumerate(s1):
            current_row = [i + 1]
            for j, c2 in enumerate(s2):
                insertions = previous_row[j + 1] + 1
                deletions = current_row[j] + 1
                substitutions = previous_row[j] + (c1 != c2)
                current_row.append(min(insertions, deletions, substitutions))
            previous_row = current_row
        
        return previous_row[-1]
    
    def find_closest_command(self, word):
        """Find the closest matching command using fuzzy matching"""
        # Check common typos first
        if word.lower() in self.common_typos:
            return self.common_typos[word.lower()]
        
        # Check Python to AbuLang conversions
        if word.lower() in self.python_to_abulang:
            return self.python_to_abulang[word.lower()]
        
        # Use difflib for fuzzy matching
        all_commands = self.keywords + self.functions
        matches = get_close_matches(word, all_commands, n=1, cutoff=0.6)
        
        if matches:
            return matches[0]
        
        # Fallback to Levenshtein distance
        min_distance = float('inf')
        closest = None
        
        for cmd in all_commands:
            distance = self.levenshtein_distance(word.lower(), cmd.lower())
            if distance < min_distance and distance <= 2:  # Max 2 character difference
                min_distance = distance
                closest = cmd
        
        return closest
    
    def fix_missing_colon(self, line):
        """Add missing colon at end of control flow statements"""
        line = line.rstrip()
        
        # Check if line needs a colon
        needs_colon = any(line.startswith(kw + ' ') for kw in 
                         ['check', 'if', 'elifi', 'elif', 'else', 'other', 
                          'loopf', 'for', 'while', 'scan', 'def'])
        
        if needs_colon and not line.endswith(':'):
            self.corrections.append(f"Added missing ':' at end of line")
            return line + ':'
        
        return line
    
    def fix_template_literal(self, line):
        """Fix unclosed template literals"""
        # Check for $" or $' template literals
        if '$"' in line or "$'" in line:
            # Count braces
            open_braces = line.count('{')
            close_braces = line.count('}')
            
            if open_braces > close_braces:
                line += '}' * (open_braces - close_braces)
                self.corrections.append(f"Added {open_braces - close_braces} missing closing brace(s)")
            
            # Check for unclosed quotes
            if line.count('$"') > line.count('"') - 1:
                line += '"'
                self.corrections.append("Added missing closing quote")
            elif line.count("$'") > line.count("'") - 1:
                line += "'"
                self.corrections.append("Added missing closing quote")
        
        return line
    
    def fix_brackets(self, line):
        """Balance brackets and parentheses"""
        open_paren = line.count('(')
        close_paren = line.count(')')
        open_bracket = line.count('[')
        close_bracket = line.count(']')
        open_brace = line.count('{')
        close_brace = line.count('}')
        
        if open_paren > close_paren:
            line += ')' * (open_paren - close_paren)
            self.corrections.append(f"Added {open_paren - close_paren} missing closing parenthesis")
        
        if open_bracket > close_bracket:
            line += ']' * (open_bracket - close_bracket)
            self.corrections.append(f"Added {open_bracket - close_bracket} missing closing bracket")
        
        if open_brace > close_brace:
            line += '}' * (open_brace - close_brace)
            self.corrections.append(f"Added {open_brace - close_brace} missing closing brace")
        
        return line
    
    def fix_quotes(self, line):
        """Balance quotes"""
        # Skip if line is a comment
        if line.strip().startswith('#') or line.strip().startswith('//'):
            return line
        
        # Count quotes (excluding escaped ones)
        double_quotes = len(re.findall(r'(?<!\\)"', line))
        single_quotes = len(re.findall(r"(?<!\\)'", line))
        
        if double_quotes % 2 != 0:
            line += '"'
            self.corrections.append("Added missing closing double quote")
        
        if single_quotes % 2 != 0:
            line += "'"
            self.corrections.append("Added missing closing single quote")
        
        return line
    
    def fix_command_typo(self, line):
        """Fix typos in commands"""
        words = line.split()
        if not words:
            return line
        
        first_word = words[0]
        
        # Check if first word is a known command
        all_commands = self.keywords + self.functions
        if first_word not in all_commands:
            closest = self.find_closest_command(first_word)
            if closest:
                words[0] = closest
                self.corrections.append(f"Auto-corrected '{first_word}' → '{closest}'")
                return ' '.join(words)
        
        return line
    
    def fix_python_syntax(self, line):
        """Convert Python syntax to AbuLang syntax"""
        original = line
        
        # elif → elifi
        if line.strip().startswith('elif '):
            line = line.replace('elif ', 'elifi ', 1)
            self.corrections.append("Converted Python 'elif' to AbuLang 'elifi'")
        
        # print() → show
        if 'print(' in line:
            line = re.sub(r'\bprint\s*\(', 'show ', line)
            line = line.rstrip(')')
            self.corrections.append("Converted Python 'print()' to AbuLang 'show'")
        
        # input() → prompt
        if 'input(' in line:
            line = re.sub(r'\binput\s*\(', 'prompt ', line)
            line = line.rstrip(')')
            self.corrections.append("Converted Python 'input()' to AbuLang 'prompt'")
        
        return line
    
    def fix_line(self, line, line_number=None):
        """
        Apply all forgiving mode fixes to a line
        Returns: (fixed_line, corrections_list)
        """
        self.corrections = []
        self.warnings = []
        
        original_line = line
        
        # Skip empty lines and comments
        if not line.strip() or line.strip().startswith('#') or line.strip().startswith('//'):
            return line, []
        
        # Apply fixes in order
        line = self.fix_command_typo(line)
        line = self.fix_python_syntax(line)
        line = self.fix_missing_colon(line)
        line = self.fix_template_literal(line)
        line = self.fix_brackets(line)
        line = self.fix_quotes(line)
        
        # Generate correction messages
        corrections = []
        if line != original_line:
            prefix = f"Line {line_number}: " if line_number else ""
            corrections.append({
                'line': line_number,
                'original': original_line.strip(),
                'fixed': line.strip(),
                'changes': self.corrections.copy()
            })
        
        return line, corrections
    
    def fix_code(self, code):
        """
        Fix an entire code block
        Returns: (fixed_code, all_corrections)
        """
        lines = code.split('\n')
        fixed_lines = []
        all_corrections = []
        
        for i, line in enumerate(lines, 1):
            fixed_line, corrections = self.fix_line(line, i)
            fixed_lines.append(fixed_line)
            all_corrections.extend(corrections)
        
        return '\n'.join(fixed_lines), all_corrections
    
    def format_corrections(self, corrections):
        """Format corrections for display"""
        if not corrections:
            return ""
        
        output = ["\n[Forgiving Mode] Auto-corrections applied:\n"]
        
        for corr in corrections:
            output.append(f"  Line {corr['line']}:")
            output.append(f"    Before: {corr['original']}")
            output.append(f"    After:  {corr['fixed']}")
            for change in corr['changes']:
                output.append(f"    • {change}")
            output.append("")
        
        return '\n'.join(output)


# Example usage
if __name__ == "__main__":
    fm = ForgivingMode()
    
    # Test cases
    test_code = """
shwo "Hello World"
check x > 5
    shwo "x is big
elifi x < 0:
    show "negative"
print("Python style")
x = (10 + 5
"""
    
    fixed_code, corrections = fm.fix_code(test_code)
    
    print("Original Code:")
    print(test_code)
    print("\nFixed Code:")
    print(fixed_code)
    print(fm.format_corrections(corrections))
