"""
Check for XSS (Cross-Site Scripting) vulnerabilities.
"""

import os
import re
from pathlib import Path
from typing import Dict, List, Optional, Any, Tuple, Set

from vulnerability_checker.checks.base import BaseCheck
from vulnerability_checker.models import CheckResult, CheckStatus, VulnerabilityIssue


class XSSCheck(BaseCheck):
    """
    Check for XSS vulnerabilities.
    """
    
    name = "xss"
    description = "Check for XSS (Cross-Site Scripting) vulnerabilities"
    
    # Patterns for finding potential XSS vulnerabilities
    XSS_PATTERNS = [
        # Flask
        r"flask\..*response.*\(.*request\..*\)",
        r"render_template\s*\(.*request\..*\)",
        r"jsonify\s*\(.*request\..*\)",
        
        # Django
        r"HttpResponse\s*\(.*request\..*\)",
        r"render\s*\(.*request\..*\)",
        r"JsonResponse\s*\(.*request\..*\)",
        
        # FastAPI
        r"HTMLResponse\s*\(.*request\..*\)",
        r"JSONResponse\s*\(.*request\..*\)",
    ]
    
    # Template engines (potential XSS)
    TEMPLATE_ENGINES = [
        # Jinja2 unsafe constructs
        r"{{\s*.*\|.*safe\s*}}",
        
        # Django unsafe constructs
        r"{%\s*autoescape\s+off\s*%}",
        r"{{\s*.*\|safe\s*}}",
    ]
    
    # Safe patterns
    SAFE_PATTERNS = [
        r"escape\s*\(",
        r"html\.escape\s*\(",
        r"bleach\.clean\s*\(",
        r"markupsafe\.escape\s*\(",
    ]
    
    def __init__(self, config: Optional[Dict[str, Any]] = None):
        super().__init__(config)
    
    def run(self, target_path: str, **kwargs) -> Tuple[CheckResult, List[VulnerabilityIssue]]:
        """
        Run check for XSS vulnerabilities.
        
        Args:
            target_path: Path to directory or file for checking
            **kwargs: Additional parameters
            
        Returns:
            Tuple[CheckResult, List[VulnerabilityIssue]]: Check result and list of found vulnerabilities
        """
        self.issues = []
        
        try:
            # Check source files for XSS vulnerabilities
            path = Path(target_path)
            for file_path in self._find_relevant_files(path):
                self._check_file_for_xss(file_path)
            
            # Create result
            status = CheckStatus.PASSED if not self.issues else CheckStatus.FAILED
            result = self.create_result(
                status=status,
                message=f"Found {len(self.issues)} potential XSS vulnerabilities" if self.issues else "No XSS vulnerabilities detected",
            )
            
            return result, self.issues
            
        except Exception as e:
            # In case of error, return ERROR status
            result = self.create_result(
                status=CheckStatus.ERROR,
                message=f"Error during XSS vulnerability check: {str(e)}",
            )
            return result, self.issues
    
    def _find_relevant_files(self, path: Path) -> Set[Path]:
        """
        Find files that may contain XSS vulnerabilities.
        
        Args:
            path: Path to directory or file
            
        Returns:
            Set[Path]: Set of paths to files
        """
        result = set()
        
        # Define file extensions to check
        extensions = {".py", ".html", ".jinja", ".jinja2", ".j2", ".tmpl"}
        
        if path.is_file():
            if path.suffix in extensions and not self.should_exclude_path(path):
                result.add(path)
            return result
        
        # Traverse directory
        for root, dirs, files in os.walk(path):
            # Filter directories to exclude
            dirs[:] = [d for d in dirs if not self.should_exclude_path(os.path.join(root, d))]
            
            for file in files:
                file_path = Path(root) / file
                if file_path.suffix in extensions and not self.should_exclude_path(file_path):
                    result.add(file_path)
        
        return result
    
    def _check_file_for_xss(self, file_path: Path) -> None:
        """
        Check file for XSS vulnerabilities.
        
        Args:
            file_path: Path to file
        """
        try:
            with open(file_path, "r", encoding="utf-8") as f:
                content = f.read()
            
            lines = content.splitlines()
            is_template = file_path.suffix in {".html", ".jinja", ".jinja2", ".j2", ".tmpl"}
            
            # Compile regular expressions
            xss_patterns = [re.compile(pattern) for pattern in self.XSS_PATTERNS]
            template_patterns = [re.compile(pattern) for pattern in self.TEMPLATE_ENGINES]
            safe_patterns = [re.compile(pattern) for pattern in self.SAFE_PATTERNS]
            
            # Check by lines
            for i, line in enumerate(lines):
                # For template files, check template engine patterns
                if is_template:
                    for pattern in template_patterns:
                        if pattern.search(line):
                            self._add_xss_issue(file_path, i + 1, line, "template")
                # For Python files, check XSS patterns
                else:
                    for pattern in xss_patterns:
                        if pattern.search(line):
                            # Check if there are no safe patterns in the same line
                            is_safe = any(safe_pattern.search(line) for safe_pattern in safe_patterns)
                            if not is_safe:
                                self._add_xss_issue(file_path, i + 1, line, "python")
        
        except Exception as e:
            # Skip files with errors
            print(f"Error checking file {file_path}: {str(e)}")
    
    def _add_xss_issue(self, file_path: Path, line_number: int, code_snippet: str, context: str) -> None:
        """
        Add XSS vulnerability to the list.
        
        Args:
            file_path: Path to file
            line_number: Line number
            code_snippet: Code fragment
            context: Context (python or template)
        """
        description = ""
        remediation = ""
        
        if context == "python":
            description = "Potential XSS vulnerability: unverified data from request used in response"
            remediation = "Use escaping functions (html.escape, markupsafe.escape) for data included in HTML"
        elif context == "template":
            description = "Potential XSS vulnerability: use of unsafe constructs in template"
            remediation = "Avoid using 'safe' filter or 'autoescape off' unless you are sure about data safety"
        
        self.add_issue(
            issue_type="Cross-Site Scripting (XSS)",
            severity="high",
            description=description,
            file_path=str(file_path),
            line_number=line_number,
            code_snippet=code_snippet.strip(),
            confidence="MEDIUM",
            cwe_id="CWE-79",
            owasp_category="A7:2017-Cross-Site Scripting (XSS)",
            remediation=remediation,
        ) 