"""
AbuLang Debug Mode (F7) - Strict Syntax Checker
Shows exact error locations with character-level precision
"""

import re


class DebugMode:
    """
    Debug Mode: Strict syntax checking with precise error locations
    """
    
    def __init__(self):
        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'
        ]
        
        self.errors = []
    
    def check_line(self, line, line_number):
        """
        Check a single line for syntax errors
        Returns list of errors with exact character positions
        """
        errors = []
        
        # Skip empty lines and comments
        if not line.strip() or line.strip().startswith('#') or line.strip().startswith('//'):
            return errors
        
        # Check for unknown commands
        words = line.split()
        if words:
            first_word = words[0]
            all_commands = self.keywords + self.functions
            
            if first_word not in all_commands and not first_word.endswith(':'):
                # Find position of the unknown command
                pos = line.find(first_word)
                errors.append({
                    'line': line_number,
                    'type': 'UnknownCommand',
                    'message': f"Unknown command '{first_word}'",
                    'position': pos,
                    'length': len(first_word),
                    'suggestion': self._find_suggestion(first_word)
                })
        
        # Check for missing colon
        needs_colon = any(line.strip().startswith(kw + ' ') for kw in 
                         ['check', 'if', 'elifi', 'elif', 'else', 'other', 
                          'loopf', 'for', 'while', 'scan', 'def'])
        
        if needs_colon and not line.rstrip().endswith(':'):
            errors.append({
                'line': line_number,
                'type': 'MissingColon',
                'message': "Missing ':' at end of control flow statement",
                'position': len(line.rstrip()),
                'length': 0,
                'suggestion': "Add ':' at the end"
            })
        
        # Check for unclosed template literals
        if '$"' in line or "$'" in line:
            open_braces = line.count('{')
            close_braces = line.count('}')
            
            if open_braces > close_braces:
                # Find position of last unclosed brace
                last_open = line.rfind('{')
                errors.append({
                    'line': line_number,
                    'type': 'UnclosedBrace',
                    'message': f"Unclosed brace in template literal ({open_braces - close_braces} missing)",
                    'position': last_open,
                    'length': 1,
                    'suggestion': "Add '}' to close the brace"
                })
            
            # Check for unclosed quotes
            if line.count('$"') > 0:
                quotes = line.count('"')
                if quotes % 2 != 0:
                    last_quote = line.rfind('"')
                    errors.append({
                        'line': line_number,
                        'type': 'UnclosedQuote',
                        'message': "Unclosed quote in template literal",
                        'position': last_quote if last_quote > 0 else len(line),
                        'length': 1,
                        'suggestion': 'Add closing quote "'
                    })
        
        # Check for unclosed brackets
        open_paren = line.count('(')
        close_paren = line.count(')')
        
        if open_paren > close_paren:
            last_open = line.rfind('(')
            errors.append({
                'line': line_number,
                'type': 'UnclosedParenthesis',
                'message': f"Unclosed parenthesis ({open_paren - close_paren} missing)",
                'position': last_open,
                'length': 1,
                'suggestion': "Add ')' to close"
            })
        
        # Check for unclosed quotes (general)
        if not (line.strip().startswith('#') or line.strip().startswith('//')):
            double_quotes = len(re.findall(r'(?<!\\)"', line))
            single_quotes = len(re.findall(r"(?<!\\)'", line))
            
            if double_quotes % 2 != 0:
                last_quote = line.rfind('"')
                errors.append({
                    'line': line_number,
                    'type': 'UnclosedQuote',
                    'message': "Unclosed double quote",
                    'position': last_quote if last_quote >= 0 else 0,
                    'length': 1,
                    'suggestion': 'Add closing "'
                })
            
            if single_quotes % 2 != 0:
                last_quote = line.rfind("'")
                errors.append({
                    'line': line_number,
                    'type': 'UnclosedQuote',
                    'message': "Unclosed single quote",
                    'position': last_quote if last_quote >= 0 else 0,
                    'length': 1,
                    'suggestion': "Add closing '"
                })
        
        return errors
    
    def _find_suggestion(self, word):
        """Find closest matching command for suggestions"""
        all_commands = self.keywords + self.functions
        
        # Simple distance calculation
        min_distance = float('inf')
        suggestion = None
        
        for cmd in all_commands:
            distance = self._levenshtein(word.lower(), cmd.lower())
            if distance < min_distance and distance <= 2:
                min_distance = distance
                suggestion = cmd
        
        return suggestion
    
    def _levenshtein(self, s1, s2):
        """Calculate Levenshtein distance"""
        if len(s1) < len(s2):
            return self._levenshtein(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 check_code(self, code):
        """
        Check entire code block for syntax errors
        Returns list of all errors with precise locations
        """
        lines = code.split('\n')
        all_errors = []
        
        for i, line in enumerate(lines, 1):
            errors = self.check_line(line, i)
            all_errors.extend(errors)
        
        return all_errors
    
    def format_error(self, error, line_content):
        """
        Format a single error with visual highlighting
        Shows the line with the error underlined and bolded
        """
        output = []
        
        # Error header
        output.append(f"\n❌ Line {error['line']}: {error['type']}")
        output.append(f"   {error['message']}")
        
        # Show the line
        output.append(f"\n   {line_content}")
        
        # Create pointer to error location
        pointer = ' ' * (3 + error['position']) + '^' * max(1, error['length'])
        output.append(pointer)
        
        # Show suggestion
        if error.get('suggestion'):
            output.append(f"   💡 Suggestion: {error['suggestion']}")
        
        return '\n'.join(output)
    
    def format_errors(self, errors, code):
        """
        Format all errors with visual highlighting
        """
        if not errors:
            return "✅ No syntax errors found!"
        
        lines = code.split('\n')
        output = [f"\n🔍 Debug Mode: Found {len(errors)} error(s)\n"]
        output.append("=" * 60)
        
        for error in errors:
            line_content = lines[error['line'] - 1] if error['line'] <= len(lines) else ""
            output.append(self.format_error(error, line_content))
            output.append("=" * 60)
        
        return '\n'.join(output)


# Example usage
if __name__ == "__main__":
    dm = DebugMode()
    
    test_code = """
shwo "Hello World"
check x > 5
    show "x is big
x = (10 + 5
"""
    
    errors = dm.check_code(test_code)
    print(dm.format_errors(errors, test_code))
