#!/usr/bin/env python3
"""
Thymeleaf Template Validator

Validates Thymeleaf template syntax and structure.
Usage: python template_validator.py <template_file.html>
"""

import sys
import re
import os
from pathlib import Path

class ThymeleafValidator:
    def __init__(self, file_path):
        self.file_path = Path(file_path)
        self.content = self.file_path.read_text(encoding='utf-8')
        self.errors = []
        self.warnings = []
        self.line_count = len(self.content.split('\n'))
    
    def validate(self):
        """Run all validation checks"""
        self.check_doctype()
        self.check_namespace()
        self.check_syntax()
        self.check_accessibility()
        self.check_security()
        self.check_performance()
        
        return len(self.errors) == 0
    
    def check_doctype(self):
        """Check for proper DOCTYPE declaration"""
        if not self.content.strip().startswith('<!DOCTYPE html>'):
            self.errors.append("Missing or incorrect DOCTYPE declaration")
    
    def check_namespace(self):
        """Check for Thymeleaf namespace declaration"""
        if 'xmlns:th="http://www.thymeleaf.org"' not in self.content:
            self.errors.append("Missing Thymeleaf namespace declaration")
        
        # Check for security namespace if security attributes are used
        if 'sec:' in self.content and 'xmlns:sec=' not in self.content:
            self.errors.append("Using security attributes without security namespace")
    
    def check_syntax(self):
        """Check common syntax errors"""
        lines = self.content.split('\n')
        
        for i, line in enumerate(lines, 1):
            # Check for unclosed expressions
            if '${' in line and line.count('${') != line.count('}'):
                self.errors.append(f"Line {i}: Unclosed expression '${{'")
            
            # Check for malformed th:attributes
            if 'th:' in line:
                self.check_th_attributes(line, i)
            
            # Check for quote mismatches
            if 'th:text=' in line:
                if line.count('"') % 2 != 0:
                    self.errors.append(f"Line {i}: Quote mismatch in th:text attribute")
    
    def check_th_attributes(self, line, line_num):
        """Validate specific th: attributes"""
        # Check th:if syntax
        if 'th:if=' in line:
            pattern = r'th:if="[^"]*"'
            if not re.search(pattern, line):
                self.errors.append("Line {}: Invalid th:if syntax".format(line_num))
        
        # Check th:each syntax
        if 'th:each=' in line:
            pattern = r'th:each="\w+\s*:\s*\$\{[^}]+\}"'
            if not re.search(pattern, line):
                self.errors.append("Line {}: Invalid th:each syntax".format(line_num))
        
        # Check th:object syntax
        if 'th:object=' in line:
            pattern = r'th:object="\$\{[^}]+\}"'
            if not re.search(pattern, line):
                self.errors.append("Line {}: Invalid th:object syntax".format(line_num))
    
    def check_accessibility(self):
        """Check for accessibility best practices"""
        lines = self.content.split('\n')
        
        for i, line in enumerate(lines, 1):
            # Check for alt attributes on images
            if '<img' in line and 'alt=' not in line and 'th:alt=' not in line:
                self.warnings.append("Line {}: Image missing alt attribute".format(i))
            
            # Check for form labels
            if '<input' in line and 'th:field=' in line:
                # Look for corresponding label
                field_name = self.extract_field_name(line)
                if field_name and not self.has_label_for_field(lines, field_name, i):
                    self.warnings.append("Line {}: Form input missing corresponding label".format(i))
            
            # Check for table headers
            if '<th>' in line and 'scope=' not in line:
                self.warnings.append("Line {}: Table header missing scope attribute".format(i))
    
    def extract_field_name(self, line):
        """Extract field name from th:field attribute"""
        match = re.search(r'th:field="\*{([^}]+)}"', line)
        return match.group(1) if match else None
    
    def has_label_for_field(self, lines, field_name, current_line):
        """Check if there's a label for a given field"""
        start = max(0, current_line - 10)
        end = min(len(lines), current_line + 10)
        
        for i in range(start, end):
            line = lines[i]
            if 'th:for="{}"'.format(field_name) in line or 'for="{}"'.format(field_name) in line:
                return True
        return False
    
    def check_security(self):
        """Check for security best practices"""
        # Check for unescaped user input
        if 'th:utext=' in self.content:
            lines_with_utext = []
            for i, line in enumerate(self.content.split('\n')):
                if 'th:utext=' in line:
                    lines_with_utext.append(i + 1)
            
            for line_num in lines_with_utext:
                self.warnings.append("Line {}: Using th:utext - ensure content is trusted".format(line_num))
        
        # Check for CSRF protection in forms
        if '<form' in self.content and 'th:action=' in self.content:
            if '_csrf' not in self.content:
                self.warnings.append("Form detected without CSRF protection")
    
    def check_performance(self):
        """Check for performance issues"""
        # Check for complex inline expressions
        lines = self.content.split('\n')
        for i, line in enumerate(lines, 1):
            if '${' in line and line.count('${') > 2:
                self.warnings.append("Line {}: Complex expression - consider simplifying".format(i))
            
            # Check for deep nesting
            if line.count('<') > 5:
                self.warnings.append("Line {}: Deep nesting - consider extracting fragments".format(i))
    
    def print_results(self):
        """Print validation results"""
        print("Validating: {}".format(self.file_path))
        print("Lines processed: {}".format(self.line_count))
        print()
        
        if self.errors:
            print("❌ ERRORS FOUND:")
            for error in self.errors:
                print("  • {}".format(error))
        else:
            print("✅ No syntax errors found")
        
        if self.warnings:
            print()
            print("⚠️  WARNINGS:")
            for warning in self.warnings:
                print("  • {}".format(warning))
        
        print()
        print("Validation complete.")

def main():
    if len(sys.argv) != 2:
        print("Usage: python template_validator.py <template_file.html>")
        sys.exit(1)
    
    file_path = sys.argv[1]
    
    if not os.path.exists(file_path):
        print("Error: File '{}' not found".format(file_path))
        sys.exit(1)
    
    validator = ThymeleafValidator(file_path)
    is_valid = validator.validate()
    validator.print_results()
    
    sys.exit(0 if is_valid else 1)

if __name__ == "__main__":
    main()