"""Message validation utilities for RateRight messaging system"""
import re
from typing import Dict, Any


def validate_message_data(data: Dict[str, Any]) -> Dict[str, Any]:
    """
    Validate message data for sending
    
    Args:
        data: Dictionary containing message data
        
    Returns:
        Dictionary with 'valid' boolean and 'message' string
    """
    errors = []
    
    # Check required fields
    if 'receiver_id' not in data:
        errors.append('receiver_id is required')
    elif not isinstance(data['receiver_id'], int) or data['receiver_id'] <= 0:
        errors.append('receiver_id must be a positive integer')
    
    if 'text' not in data:
        errors.append('text is required')
    else:
        text = str(data['text']).strip()
        
        # Check text length
        if not text:
            errors.append('Message text cannot be empty')
        elif len(text) > 2000:
            errors.append('Message text too long (max 2000 characters)')
        elif len(text) < 1:
            errors.append('Message text must be at least 1 character')
    
    # Optional fields validation
    if 'contract_id' in data and data['contract_id'] is not None:
        if not isinstance(data['contract_id'], int) or data['contract_id'] <= 0:
            errors.append('contract_id must be a positive integer')
    
    if 'job_id' in data and data['job_id'] is not None:
        if not isinstance(data['job_id'], int) or data['job_id'] <= 0:
            errors.append('job_id must be a positive integer')
    
    return {
        'valid': len(errors) == 0,
        'message': '; '.join(errors) if errors else 'Valid',
        'errors': errors
    }


def sanitize_message_text(text: str) -> str:
    """
    Sanitize message text to remove potentially harmful content
    
    Args:
        text: Raw message text
        
    Returns:
        Sanitized message text
    """
    if not text:
        return ""
    
    # Convert to string and strip whitespace
    text = str(text).strip()
    
    # Remove potentially harmful characters/patterns
    # Remove null bytes
    text = text.replace('\x00', '')
    
    # Remove excessive whitespace (replace multiple spaces/newlines with single)
    text = re.sub(r'\s+', ' ', text)
    
    # Limit length
    if len(text) > 2000:
        text = text[:2000]
    
    # Remove potentially dangerous HTML/script tags
    text = re.sub(r'<script[^>]*>.*?</script>', '', text, flags=re.IGNORECASE | re.DOTALL)
    text = re.sub(r'<iframe[^>]*>.*?</iframe>', '', text, flags=re.IGNORECASE | re.DOTALL)
    text = re.sub(r'javascript:', '', text, flags=re.IGNORECASE)
    
    return text.strip()


def validate_pagination_params(limit: Any, offset: Any) -> Dict[str, Any]:
    """
    Validate pagination parameters
    
    Args:
        limit: Limit parameter
        offset: Offset parameter
        
    Returns:
        Dictionary with validated limit and offset, and any errors
    """
    errors = []
    validated_limit = 50  # Default
    validated_offset = 0   # Default
    
    # Validate limit
    try:
        if limit is not None:
            validated_limit = int(limit)
            if validated_limit <= 0:
                errors.append('limit must be positive')
                validated_limit = 50
            elif validated_limit > 100:
                errors.append('limit cannot exceed 100')
                validated_limit = 100
    except (ValueError, TypeError):
        errors.append('limit must be a valid integer')
        validated_limit = 50
    
    # Validate offset
    try:
        if offset is not None:
            validated_offset = int(offset)
            if validated_offset < 0:
                errors.append('offset cannot be negative')
                validated_offset = 0
    except (ValueError, TypeError):
        errors.append('offset must be a valid integer')
        validated_offset = 0
    
    return {
        'valid': len(errors) == 0,
        'limit': validated_limit,
        'offset': validated_offset,
        'errors': errors
    }


def validate_search_query(query: str) -> Dict[str, Any]:
    """
    Validate search query
    
    Args:
        query: Search query string
        
    Returns:
        Dictionary with validation results and sanitized query
    """
    errors = []
    
    if not query:
        errors.append('Search query cannot be empty')
        return {'valid': False, 'query': '', 'errors': errors}
    
    # Sanitize query
    query = str(query).strip()
    
    # Check length
    if len(query) < 2:
        errors.append('Search query must be at least 2 characters')
    elif len(query) > 100:
        errors.append('Search query too long (max 100 characters)')
        query = query[:100]
    
    # Remove potentially harmful patterns
    query = re.sub(r'[<>"\']', '', query)  # Remove HTML-like characters
    query = re.sub(r'[;(){}[\]]', '', query)  # Remove SQL injection characters
    
    return {
        'valid': len(errors) == 0,
        'query': query,
        'errors': errors
    }


def validate_timestamp(timestamp_str: str) -> Dict[str, Any]:
    """
    Validate timestamp format for polling
    
    Args:
        timestamp_str: ISO format timestamp string
        
    Returns:
        Dictionary with validation results and parsed datetime
    """
    from datetime import datetime, timezone
    
    if not timestamp_str:
        return {'valid': True, 'datetime': None, 'errors': []}
    
    try:
        # Handle different timestamp formats
        if timestamp_str.endswith('Z'):
            timestamp_str = timestamp_str[:-1] + '+00:00'
        
        dt = datetime.fromisoformat(timestamp_str)
        
        # Check if timestamp is reasonable (not too far in future/past)
        now = datetime.now(timezone.utc)
        max_age = now - datetime(2020, 1, 1)  # Not older than 2020
        max_future = now + max_age  # Not too far in future
        
        if dt < datetime(2020, 1, 1):
            return {'valid': False, 'datetime': None, 'errors': ['Timestamp too old']}
        
        if dt > max_future:
            return {'valid': False, 'datetime': None, 'errors': ['Timestamp too far in future']}
        
        return {'valid': True, 'datetime': dt, 'errors': []}
        
    except ValueError as e:
        return {'valid': False, 'datetime': None, 'errors': [f'Invalid timestamp format: {str(e)}']}


def validate_user_access(user_id: int, partner_id: int) -> Dict[str, Any]:
    """
    Validate that user has access to message/conversation
    
    Args:
        user_id: Current user ID
        partner_id: Partner user ID
        
    Returns:
        Dictionary with validation results
    """
    errors = []
    
    # Check if user IDs are valid
    if user_id == partner_id:
        errors.append('Cannot message yourself')
    
    if user_id <= 0:
        errors.append('Invalid user ID')
    
    if partner_id <= 0:
        errors.append('Invalid partner ID')
    
    return {
        'valid': len(errors) == 0,
        'errors': errors
    }


def format_error_response(errors: list, status_code: int = 400) -> tuple:
    """
    Format error response for API endpoints
    
    Args:
        errors: List of error messages
        status_code: HTTP status code
        
    Returns:
        Tuple of (response_dict, status_code)
    """
    return {
        'success': False,
        'error': errors[0] if len(errors) == 1 else 'Multiple validation errors',
        'errors': errors if len(errors) > 1 else None
    }, status_code


def format_success_response(data: Any = None, message: str = None) -> tuple:
    """
    Format success response for API endpoints
    
    Args:
        data: Response data
        message: Success message
        
    Returns:
        Tuple of (response_dict, status_code)
    """
    response = {'success': True}
    
    if message:
        response['message'] = message
    
    if data is not None:
        if isinstance(data, dict):
            response.update(data)
        else:
            response['data'] = data
    
    return response, 200


# Aliases for backwards compatibility with tests
def validate_message_content(content: str) -> bool:
    """Validate message content - alias for existing validation"""
    if not content or not isinstance(content, str):
        return False
    
    # Check original length before sanitization
    if len(content) > 5000:
        return False
    
    sanitized = sanitize_message_text(content)
    return len(sanitized.strip()) > 0


def sanitize_message(text: str) -> str:
    """Sanitize message - alias for sanitize_message_text"""
    return sanitize_message_text(text)
