"""
Syntax Checker Utility for Code Assistant Bot
Author: RSK World (https://rskworld.in)
Founder: Molla Samser
Designer & Tester: Rima Khatun
Contact: help@rskworld.in, +91 93305 39277
Year: 2026
"""

import ast
import re
import subprocess
import tempfile
import os
from typing import Dict, List, Any, Tuple

class SyntaxChecker:
    """
    Utility class for checking syntax errors in various programming languages
    """
    
    def __init__(self):
        self.supported_languages = [
            'python', 'javascript', 'java', 'cpp', 'c', 'csharp',
            'php', 'ruby', 'go', 'rust', 'typescript', 'html', 'css'
        ]
    
    def check_syntax(self, code: str, language: str) -> Dict[str, Any]:
        """
        Check syntax for the given code and language
        """
        try:
            if language not in self.supported_languages:
                return {
                    'valid': False,
                    'error': f'Language {language} is not supported',
                    'errors': [],
                    'warnings': []
                }
            
            # Language-specific syntax checking
            if language == 'python':
                return self._check_python_syntax(code)
            elif language in ['javascript', 'typescript']:
                return self._check_javascript_syntax(code, language)
            elif language == 'java':
                return self._check_java_syntax(code)
            elif language in ['cpp', 'c']:
                return self._check_cpp_syntax(code, language)
            elif language == 'csharp':
                return self._check_csharp_syntax(code)
            elif language == 'php':
                return self._check_php_syntax(code)
            elif language == 'ruby':
                return self._check_ruby_syntax(code)
            elif language == 'go':
                return self._check_go_syntax(code)
            elif language == 'rust':
                return self._check_rust_syntax(code)
            elif language == 'html':
                return self._check_html_syntax(code)
            elif language == 'css':
                return self._check_css_syntax(code)
            else:
                return {
                    'valid': True,
                    'error': None,
                    'errors': [],
                    'warnings': ['Syntax checking not implemented for this language']
                }
                
        except Exception as e:
            return {
                'valid': False,
                'error': f'Syntax checking failed: {str(e)}',
                'errors': [{'line': 0, 'column': 0, 'message': str(e)}],
                'warnings': []
            }
    
    def _check_python_syntax(self, code: str) -> Dict[str, Any]:
        """Check Python syntax using AST"""
        try:
            # Parse the code
            ast.parse(code)
            
            # Additional checks
            warnings = self._check_python_style(code)
            
            return {
                'valid': True,
                'error': None,
                'errors': [],
                'warnings': warnings
            }
            
        except SyntaxError as e:
            return {
                'valid': False,
                'error': 'Syntax error detected',
                'errors': [{
                    'line': e.lineno or 0,
                    'column': e.offset or 0,
                    'message': e.msg or 'Unknown syntax error'
                }],
                'warnings': []
            }
        except Exception as e:
            return {
                'valid': False,
                'error': f'Parse error: {str(e)}',
                'errors': [{'line': 0, 'column': 0, 'message': str(e)}],
                'warnings': []
            }
    
    def _check_javascript_syntax(self, code: str, language: str) -> Dict[str, Any]:
        """Check JavaScript/TypeScript syntax"""
        try:
            # Basic syntax checks using regex patterns
            errors = []
            warnings = []
            
            # Check for unmatched brackets
            bracket_pairs = {'(': ')', '[': ']', '{': '}'}
            stack = []
            
            for i, char in enumerate(code):
                if char in bracket_pairs:
                    stack.append((char, i))
                elif char in bracket_pairs.values():
                    if not stack:
                        errors.append({
                            'line': code[:i].count('\n') + 1,
                            'column': i - code.rfind('\n', 0, i) - 1,
                            'message': f'Unmatched closing bracket: {char}'
                        })
                    else:
                        open_bracket, _ = stack.pop()
                        expected_close = bracket_pairs[open_bracket]
                        if char != expected_close:
                            errors.append({
                                'line': code[:i].count('\n') + 1,
                                'column': i - code.rfind('\n', 0, i) - 1,
                                'message': f'Expected {expected_close} but found {char}'
                            })
            
            # Check for unclosed brackets
            for open_bracket, pos in stack:
                errors.append({
                    'line': code[:pos].count('\n') + 1,
                    'column': pos - code.rfind('\n', 0, pos) - 1,
                    'message': f'Unclosed bracket: {open_bracket}'
                })
            
            # Check for common issues
            if '==' in code and '===' not in code:
                warnings.append({
                    'line': 0,
                    'column': 0,
                    'message': 'Consider using === instead of == for strict equality'
                })
            
            # Check for missing semicolons (basic check)
            lines = code.split('\n')
            for i, line in enumerate(lines):
                stripped = line.strip()
                if (stripped and 
                    not stripped.endswith(('{', '}', ';', ',', '(', ')', '[', ']')) and
                    not any(keyword in stripped for keyword in ['if', 'for', 'while', 'function', 'else', 'try', 'catch', 'finally', 'class', 'return', 'break', 'continue']) and
                    not stripped.startswith('//') and
                    not stripped.startswith('/*')):
                    warnings.append({
                        'line': i + 1,
                        'column': len(line),
                        'message': 'Missing semicolon at end of line'
                    })
            
            return {
                'valid': len(errors) == 0,
                'error': None if len(errors) == 0 else 'Syntax errors detected',
                'errors': errors,
                'warnings': warnings
            }
            
        except Exception as e:
            return {
                'valid': False,
                'error': f'JavaScript syntax check failed: {str(e)}',
                'errors': [{'line': 0, 'column': 0, 'message': str(e)}],
                'warnings': []
            }
    
    def _check_java_syntax(self, code: str) -> Dict[str, Any]:
        """Check Java syntax (basic checks)"""
        try:
            errors = []
            warnings = []
            
            # Check for class declaration
            if not re.search(r'\bclass\s+\w+', code):
                warnings.append({
                    'line': 0,
                    'column': 0,
                    'message': 'No class declaration found'
                })
            
            # Check for main method
            if not re.search(r'public\s+static\s+void\s+main\s*\(\s*String\s*\[\s*\]\s*\w+\s*\)', code):
                warnings.append({
                    'line': 0,
                    'column': 0,
                    'message': 'No main method found'
                })
            
            # Check for unmatched brackets
            bracket_errors = self._check_brackets(code)
            errors.extend(bracket_errors)
            
            return {
                'valid': len(errors) == 0,
                'error': None if len(errors) == 0 else 'Syntax errors detected',
                'errors': errors,
                'warnings': warnings
            }
            
        except Exception as e:
            return {
                'valid': False,
                'error': f'Java syntax check failed: {str(e)}',
                'errors': [{'line': 0, 'column': 0, 'message': str(e)}],
                'warnings': []
            }
    
    def _check_cpp_syntax(self, code: str, language: str) -> Dict[str, Any]:
        """Check C/C++ syntax (basic checks)"""
        try:
            errors = []
            warnings = []
            
            # Check for main function
            if not re.search(r'int\s+main\s*\(', code):
                warnings.append({
                    'line': 0,
                    'column': 0,
                    'message': 'No main function found'
                })
            
            # Check for include statements
            if not re.search(r'#include\s*<[^>]+>', code):
                warnings.append({
                    'line': 0,
                    'column': 0,
                    'message': 'No include statements found'
                })
            
            # Check for unmatched brackets
            bracket_errors = self._check_brackets(code)
            errors.extend(bracket_errors)
            
            # Check for missing semicolons
            lines = code.split('\n')
            for i, line in enumerate(lines):
                stripped = line.strip()
                if (stripped and 
                    not stripped.endswith(('{', '}', ';', ',', '(', ')', '[', ']', ':', '//')) and
                    not any(keyword in stripped for keyword in ['if', 'for', 'while', 'else', 'switch', 'case', 'default', 'return', 'break', 'continue', 'using', 'namespace']) and
                    not stripped.startswith('#') and
                    not stripped.startswith('//')):
                    warnings.append({
                        'line': i + 1,
                        'column': len(line),
                        'message': 'Missing semicolon at end of line'
                    })
            
            return {
                'valid': len(errors) == 0,
                'error': None if len(errors) == 0 else 'Syntax errors detected',
                'errors': errors,
                'warnings': warnings
            }
            
        except Exception as e:
            return {
                'valid': False,
                'error': f'C/C++ syntax check failed: {str(e)}',
                'errors': [{'line': 0, 'column': 0, 'message': str(e)}],
                'warnings': []
            }
    
    def _check_csharp_syntax(self, code: str) -> Dict[str, Any]:
        """Check C# syntax (basic checks)"""
        try:
            errors = []
            warnings = []
            
            # Check for class declaration
            if not re.search(r'\bclass\s+\w+', code):
                warnings.append({
                    'line': 0,
                    'column': 0,
                    'message': 'No class declaration found'
                })
            
            # Check for Main method
            if not re.search(r'static\s+void\s+Main\s*\(', code):
                warnings.append({
                    'line': 0,
                    'column': 0,
                    'message': 'No Main method found'
                })
            
            # Check for using statements
            if not re.search(r'using\s+\w+(?:\.\w+)*\s*;', code):
                warnings.append({
                    'line': 0,
                    'column': 0,
                    'message': 'No using statements found'
                })
            
            # Check for unmatched brackets
            bracket_errors = self._check_brackets(code)
            errors.extend(bracket_errors)
            
            return {
                'valid': len(errors) == 0,
                'error': None if len(errors) == 0 else 'Syntax errors detected',
                'errors': errors,
                'warnings': warnings
            }
            
        except Exception as e:
            return {
                'valid': False,
                'error': f'C# syntax check failed: {str(e)}',
                'errors': [{'line': 0, 'column': 0, 'message': str(e)}],
                'warnings': []
            }
    
    def _check_php_syntax(self, code: str) -> Dict[str, Any]:
        """Check PHP syntax (basic checks)"""
        try:
            errors = []
            warnings = []
            
            # Check for PHP tags
            if not re.search(r'<\?php', code):
                warnings.append({
                    'line': 0,
                    'column': 0,
                    'message': 'No PHP opening tag found'
                })
            
            # Check for unmatched brackets
            bracket_errors = self._check_brackets(code)
            errors.extend(bracket_errors)
            
            return {
                'valid': len(errors) == 0,
                'error': None if len(errors) == 0 else 'Syntax errors detected',
                'errors': errors,
                'warnings': warnings
            }
            
        except Exception as e:
            return {
                'valid': False,
                'error': f'PHP syntax check failed: {str(e)}',
                'errors': [{'line': 0, 'column': 0, 'message': str(e)}],
                'warnings': []
            }
    
    def _check_ruby_syntax(self, code: str) -> Dict[str, Any]:
        """Check Ruby syntax (basic checks)"""
        try:
            errors = []
            warnings = []
            
            # Check for unmatched brackets
            bracket_errors = self._check_brackets(code)
            errors.extend(bracket_errors)
            
            # Check for end statements
            do_count = len(re.findall(r'\bdo\b', code))
            end_count = len(re.findall(r'\bend\b', code))
            
            if do_count != end_count:
                errors.append({
                    'line': 0,
                    'column': 0,
                    'message': f'Mismatched do/end blocks: {do_count} do, {end_count} end'
                })
            
            return {
                'valid': len(errors) == 0,
                'error': None if len(errors) == 0 else 'Syntax errors detected',
                'errors': errors,
                'warnings': warnings
            }
            
        except Exception as e:
            return {
                'valid': False,
                'error': f'Ruby syntax check failed: {str(e)}',
                'errors': [{'line': 0, 'column': 0, 'message': str(e)}],
                'warnings': []
            }
    
    def _check_go_syntax(self, code: str) -> Dict[str, Any]:
        """Check Go syntax (basic checks)"""
        try:
            errors = []
            warnings = []
            
            # Check for package declaration
            if not re.search(r'package\s+\w+', code):
                warnings.append({
                    'line': 0,
                    'column': 0,
                    'message': 'No package declaration found'
                })
            
            # Check for main function
            if not re.search(r'func\s+main\s*\(', code):
                warnings.append({
                    'line': 0,
                    'column': 0,
                    'message': 'No main function found'
                })
            
            # Check for unmatched brackets
            bracket_errors = self._check_brackets(code)
            errors.extend(bracket_errors)
            
            return {
                'valid': len(errors) == 0,
                'error': None if len(errors) == 0 else 'Syntax errors detected',
                'errors': errors,
                'warnings': warnings
            }
            
        except Exception as e:
            return {
                'valid': False,
                'error': f'Go syntax check failed: {str(e)}',
                'errors': [{'line': 0, 'column': 0, 'message': str(e)}],
                'warnings': []
            }
    
    def _check_rust_syntax(self, code: str) -> Dict[str, Any]:
        """Check Rust syntax (basic checks)"""
        try:
            errors = []
            warnings = []
            
            # Check for fn main
            if not re.search(r'fn\s+main\s*\(', code):
                warnings.append({
                    'line': 0,
                    'column': 0,
                    'message': 'No main function found'
                })
            
            # Check for unmatched brackets
            bracket_errors = self._check_brackets(code)
            errors.extend(bracket_errors)
            
            return {
                'valid': len(errors) == 0,
                'error': None if len(errors) == 0 else 'Syntax errors detected',
                'errors': errors,
                'warnings': warnings
            }
            
        except Exception as e:
            return {
                'valid': False,
                'error': f'Rust syntax check failed: {str(e)}',
                'errors': [{'line': 0, 'column': 0, 'message': str(e)}],
                'warnings': []
            }
    
    def _check_html_syntax(self, code: str) -> Dict[str, Any]:
        """Check HTML syntax (basic checks)"""
        try:
            errors = []
            warnings = []
            
            # Check for unmatched tags
            tag_pattern = r'<(/?)([a-zA-Z][a-zA-Z0-9]*)\b[^>]*>'
            tags = re.finditer(tag_pattern, code)
            
            stack = []
            for match in tags:
                is_closing = match.group(1) == '/'
                tag_name = match.group(2).lower()
                position = match.start()
                
                # Skip self-closing tags
                if match.group(0).endswith('/>') or tag_name in ['br', 'hr', 'img', 'meta', 'link', 'input']:
                    continue
                
                if is_closing:
                    if not stack or stack[-1] != tag_name:
                        errors.append({
                            'line': code[:position].count('\n') + 1,
                            'column': position - code.rfind('\n', 0, position) - 1,
                            'message': f'Unexpected closing tag: {tag_name}'
                        })
                    else:
                        stack.pop()
                else:
                    stack.append(tag_name)
            
            # Check for unclosed tags
            for tag in stack:
                errors.append({
                    'line': 0,
                    'column': 0,
                    'message': f'Unclosed tag: {tag}'
                })
            
            return {
                'valid': len(errors) == 0,
                'error': None if len(errors) == 0 else 'HTML syntax errors detected',
                'errors': errors,
                'warnings': warnings
            }
            
        except Exception as e:
            return {
                'valid': False,
                'error': f'HTML syntax check failed: {str(e)}',
                'errors': [{'line': 0, 'column': 0, 'message': str(e)}],
                'warnings': []
            }
    
    def _check_css_syntax(self, code: str) -> Dict[str, Any]:
        """Check CSS syntax (basic checks)"""
        try:
            errors = []
            warnings = []
            
            # Check for unmatched braces
            open_braces = code.count('{')
            close_braces = code.count('}')
            
            if open_braces != close_braces:
                errors.append({
                    'line': 0,
                    'column': 0,
                    'message': f'Unmatched braces: {open_braces} opening, {close_braces} closing'
                })
            
            # Check for invalid selectors (basic check)
            selector_pattern = r'([^{]+)\s*\{'
            matches = re.finditer(selector_pattern, code)
            
            for match in matches:
                selector = match.group(1).strip()
                if not selector:
                    errors.append({
                        'line': code[:match.start()].count('\n') + 1,
                        'column': match.start() - code.rfind('\n', 0, match.start()) - 1,
                        'message': 'Empty selector found'
                    })
            
            return {
                'valid': len(errors) == 0,
                'error': None if len(errors) == 0 else 'CSS syntax errors detected',
                'errors': errors,
                'warnings': warnings
            }
            
        except Exception as e:
            return {
                'valid': False,
                'error': f'CSS syntax check failed: {str(e)}',
                'errors': [{'line': 0, 'column': 0, 'message': str(e)}],
                'warnings': []
            }
    
    def _check_brackets(self, code: str) -> List[Dict[str, Any]]:
        """Check for unmatched brackets"""
        errors = []
        bracket_pairs = {'(': ')', '[': ']', '{': '}'}
        stack = []
        
        for i, char in enumerate(code):
            if char in bracket_pairs:
                stack.append((char, i))
            elif char in bracket_pairs.values():
                if not stack:
                    errors.append({
                        'line': code[:i].count('\n') + 1,
                        'column': i - code.rfind('\n', 0, i) - 1,
                        'message': f'Unmatched closing bracket: {char}'
                    })
                else:
                    open_bracket, _ = stack.pop()
                    expected_close = bracket_pairs[open_bracket]
                    if char != expected_close:
                        errors.append({
                            'line': code[:i].count('\n') + 1,
                            'column': i - code.rfind('\n', 0, i) - 1,
                            'message': f'Expected {expected_close} but found {char}'
                        })
        
        # Check for unclosed brackets
        for open_bracket, pos in stack:
            errors.append({
                'line': code[:pos].count('\n') + 1,
                'column': pos - code.rfind('\n', 0, pos) - 1,
                'message': f'Unclosed bracket: {open_bracket}'
            })
        
        return errors
    
    def _check_python_style(self, code: str) -> List[Dict[str, Any]]:
        """Check Python code style issues"""
        warnings = []
        lines = code.split('\n')
        
        for i, line in enumerate(lines):
            stripped = line.strip()
            
            # Check line length
            if len(line) > 79:
                warnings.append({
                    'line': i + 1,
                    'column': 80,
                    'message': f'Line too long ({len(line)} > 79 characters)'
                })
            
            # Check for trailing whitespace
            if line.endswith(' ') or line.endswith('\t'):
                warnings.append({
                    'line': i + 1,
                    'column': len(line),
                    'message': 'Trailing whitespace'
                })
            
            # Check for missing docstring in functions
            if stripped.startswith('def ') and ':' in stripped:
                next_line = lines[i + 1] if i + 1 < len(lines) else ''
                if not next_line.strip().startswith('"""') and not next_line.strip().startswith("'''"):
                    warnings.append({
                        'line': i + 1,
                        'column': len(stripped),
                        'message': 'Missing docstring in function'
                    })
        
        return warnings
