"""
Input validation utilities for security.
"""
import re
from typing import Optional
from fastapi import HTTPException, status


class InputValidator:
    """Input validation for security."""
    
    # Regex patterns
    EMAIL_PATTERN = re.compile(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$')
    USERNAME_PATTERN = re.compile(r'^[a-zA-Z0-9_-]{3,50}$')
    
    # Dangerous patterns (basic SQL injection prevention)
    SQL_INJECTION_PATTERNS = [
        r"(\b(SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC|EXECUTE)\b)",
        r"(--|;|\/\*|\*\/)",
        r"(\bOR\b.*=.*)",
        r"(\bAND\b.*=.*)",
        r"('|(\\x27)|(\\x22))",
    ]
    
    # XSS patterns
    XSS_PATTERNS = [
        r"<script[^>]*>.*?</script>",
        r"javascript:",
        r"onerror\s*=",
        r"onload\s*=",
    ]
    
    @staticmethod
    def validate_email(email: str) -> str:
        """Validate email format.
        
        Args:
            email: Email address to validate
            
        Returns:
            Validated email
            
        Raises:
            HTTPException: If email is invalid
        """
        if not email or len(email) > 100:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Invalid email address"
            )
        
        if not InputValidator.EMAIL_PATTERN.match(email):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Invalid email format"
            )
        
        return email.lower().strip()
    
    @staticmethod
    def validate_username(username: str) -> str:
        """Validate username format.
        
        Args:
            username: Username to validate
            
        Returns:
            Validated username
            
        Raises:
            HTTPException: If username is invalid
        """
        if not username:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Username is required"
            )
        
        if not InputValidator.USERNAME_PATTERN.match(username):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Username must be 3-50 characters and contain only letters, numbers, underscore, or hyphen"
            )
        
        return username.strip()
    
    @staticmethod
    def validate_password(password: str) -> str:
        """Validate password strength.
        
        Args:
            password: Password to validate
            
        Returns:
            Validated password
            
        Raises:
            HTTPException: If password is weak
        """
        if not password:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Password is required"
            )
        
        if len(password) < 8:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Password must be at least 8 characters long"
            )
        
        if len(password) > 128:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Password is too long"
            )
        
        # Check for complexity
        has_upper = any(c.isupper() for c in password)
        has_lower = any(c.islower() for c in password)
        has_digit = any(c.isdigit() for c in password)
        
        if not (has_upper and has_lower and has_digit):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Password must contain uppercase, lowercase, and numbers"
            )
        
        return password
    
    @staticmethod
    def sanitize_string(text: str, max_length: int = 1000) -> str:
        """Sanitize user input string.
        
        Args:
            text: Text to sanitize
            max_length: Maximum allowed length
            
        Returns:
            Sanitized text
            
        Raises:
            HTTPException: If text contains dangerous patterns
        """
        if not text:
            return ""
        
        # Check length
        if len(text) > max_length:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Input too long (max {max_length} characters)"
            )
        
        # Check for SQL injection
        for pattern in InputValidator.SQL_INJECTION_PATTERNS:
            if re.search(pattern, text, re.IGNORECASE):
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="Invalid input detected"
                )
        
        # Check for XSS
        for pattern in InputValidator.XSS_PATTERNS:
            if re.search(pattern, text, re.IGNORECASE):
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="Invalid input detected"
                )
        
        return text.strip()
    
    @staticmethod
    def validate_project_name(name: str) -> str:
        """Validate project name.
        
        Args:
            name: Project name
            
        Returns:
            Validated name
        """
        return InputValidator.sanitize_string(name, max_length=200)
    
    @staticmethod
    def validate_prompt(prompt: str) -> str:
        """Validate AI prompt.
        
        Args:
            prompt: Prompt text
            
        Returns:
            Validated prompt
        """
        if not prompt:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Prompt is required"
            )
        
        return InputValidator.sanitize_string(prompt, max_length=5000)
