"""
Validation Utilities

Common validation functions.
"""

import re
import html
from typing import Optional
from uuid import UUID


# Email regex pattern
EMAIL_PATTERN = re.compile(
    r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
)

# Phone pattern (international format)
PHONE_PATTERN = re.compile(
    r"^[\+]?[(]?[0-9]{1,4}[)]?[-\s\./0-9]*$"
)

# URL pattern
URL_PATTERN = re.compile(
    r"^https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+"
    r"(?::\d+)?(?:/[-\w%!$.&'()*+,;:=@]*)*"
    r"(?:\?[-\w%!$.&'()*+,;:=@/?]*)?(?:#[-\w%!$.&'()*+,;:=@/?]*)?$"
)


def is_valid_email(email: str) -> bool:
    """
    Validate email address format.
    
    Args:
        email: Email address to validate
        
    Returns:
        True if valid email format
    """
    if not email or len(email) > 254:
        return False
    return bool(EMAIL_PATTERN.match(email))


def is_valid_phone(phone: str) -> bool:
    """
    Validate phone number format.
    
    Args:
        phone: Phone number to validate
        
    Returns:
        True if valid phone format
    """
    if not phone:
        return False
    # Remove common formatting characters for validation
    clean_phone = re.sub(r"[\s\-\.\(\)]", "", phone)
    if len(clean_phone) < 7 or len(clean_phone) > 15:
        return False
    return bool(PHONE_PATTERN.match(phone))


def is_valid_url(url: str) -> bool:
    """
    Validate URL format.
    
    Args:
        url: URL to validate
        
    Returns:
        True if valid URL format
    """
    if not url or len(url) > 2048:
        return False
    return bool(URL_PATTERN.match(url))


def is_valid_uuid(value: str) -> bool:
    """
    Validate UUID format.
    
    Args:
        value: Value to validate
        
    Returns:
        True if valid UUID format
    """
    try:
        UUID(value)
        return True
    except (ValueError, TypeError):
        return False


def sanitize_html(html_content: str, allowed_tags: Optional[list[str]] = None) -> str:
    """
    Sanitize HTML content by escaping or removing dangerous elements.
    
    Args:
        html_content: HTML content to sanitize
        allowed_tags: Optional list of allowed HTML tags
        
    Returns:
        Sanitized HTML content
    """
    if allowed_tags is None:
        # Default: escape all HTML
        return html.escape(html_content)
    
    # Simple tag stripping (for production, use a library like bleach)
    result = html_content
    
    # Remove script and style tags completely
    result = re.sub(r"<script[^>]*>.*?</script>", "", result, flags=re.DOTALL | re.IGNORECASE)
    result = re.sub(r"<style[^>]*>.*?</style>", "", result, flags=re.DOTALL | re.IGNORECASE)
    
    # Remove event handlers
    result = re.sub(r'\s+on\w+\s*=\s*["\'][^"\']*["\']', "", result, flags=re.IGNORECASE)
    
    # Remove javascript: URLs
    result = re.sub(r'href\s*=\s*["\']javascript:[^"\']*["\']', "", result, flags=re.IGNORECASE)
    
    return result


def is_strong_password(
    password: str,
    min_length: int = 8,
    require_uppercase: bool = True,
    require_lowercase: bool = True,
    require_digit: bool = True,
    require_special: bool = True,
) -> tuple[bool, list[str]]:
    """
    Validate password strength.
    
    Args:
        password: Password to validate
        min_length: Minimum length requirement
        require_uppercase: Require uppercase letter
        require_lowercase: Require lowercase letter
        require_digit: Require digit
        require_special: Require special character
        
    Returns:
        Tuple of (is_valid, list_of_errors)
    """
    errors = []
    
    if len(password) < min_length:
        errors.append(f"Password must be at least {min_length} characters")
    
    if require_uppercase and not re.search(r"[A-Z]", password):
        errors.append("Password must contain at least one uppercase letter")
    
    if require_lowercase and not re.search(r"[a-z]", password):
        errors.append("Password must contain at least one lowercase letter")
    
    if require_digit and not re.search(r"\d", password):
        errors.append("Password must contain at least one digit")
    
    if require_special and not re.search(r"[!@#$%^&*(),.?\":{}|<>]", password):
        errors.append("Password must contain at least one special character")
    
    return len(errors) == 0, errors


def normalize_phone(phone: str, country_code: str = "+1") -> str:
    """
    Normalize phone number to E.164 format.
    
    Args:
        phone: Phone number
        country_code: Default country code
        
    Returns:
        Normalized phone number
    """
    # Remove all non-digit characters except leading +
    clean = re.sub(r"[^\d+]", "", phone)
    
    # If no country code, add default
    if not clean.startswith("+"):
        clean = country_code + clean
    
    return clean
