"""Input validation and sanitization"""
from typing import Dict, Any, Optional, List
import re
from datetime import datetime

class ValidationError(Exception):
    """Raised when validation fails"""
    pass


class Validator:
    """Input validator with common patterns"""

    @staticmethod
    def validate_user_id(user_id: str) -> str:
        """
        Validate user ID format.

        Args:
            user_id: User ID to validate

        Returns:
            Sanitized user ID

        Raises:
            ValidationError: If invalid
        """
        if not user_id or not isinstance(user_id, str):
            raise ValidationError("User ID must be a non-empty string")

        # Only allow alphanumeric, dash, underscore
        if not re.match(r'^[a-zA-Z0-9_-]+$', user_id):
            raise ValidationError("User ID contains invalid characters")

        if len(user_id) > 64:
            raise ValidationError("User ID too long (max 64 characters)")

        return user_id

    @staticmethod
    def validate_command(command: str) -> str:
        """
        Validate game command.

        Args:
            command: Command string

        Returns:
            Validated command

        Raises:
            ValidationError: If invalid
        """
        valid_commands = {'start', 'stop', 'restart', 'pause', 'resume'}

        if command not in valid_commands:
            raise ValidationError(f"Invalid command. Must be one of: {valid_commands}")

        return command

    @staticmethod
    def validate_speed(speed: Any) -> int:
        """
        Validate game speed.

        Args:
            speed: Speed value

        Returns:
            Validated speed as int

        Raises:
            ValidationError: If invalid
        """
        try:
            speed_int = int(speed)
        except (ValueError, TypeError):
            raise ValidationError("Speed must be a number")

        if not (1 <= speed_int <= 5000):
            raise ValidationError("Speed must be between 1 and 5000")

        return speed_int

    @staticmethod
    def validate_answer_id(answer_id: str) -> str:
        """
        Validate question/answer ID.

        Args:
            answer_id: Answer ID to validate

        Returns:
            Sanitized answer ID

        Raises:
            ValidationError: If invalid
        """
        if not answer_id or not isinstance(answer_id, str):
            raise ValidationError("Answer ID must be a non-empty string")

        # Only allow alphanumeric and underscore (function names)
        if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', answer_id):
            raise ValidationError("Answer ID contains invalid characters")

        if len(answer_id) > 128:
            raise ValidationError("Answer ID too long")

        return answer_id

    @staticmethod
    def validate_response_text(response: str) -> str:
        """
        Validate and sanitize response text.

        Args:
            response: Response text

        Returns:
            Sanitized response

        Raises:
            ValidationError: If invalid
        """
        if not isinstance(response, str):
            raise ValidationError("Response must be a string")

        # Limit length
        if len(response) > 10000:
            raise ValidationError("Response too long (max 10000 characters)")

        # Strip dangerous HTML/script tags
        response = re.sub(r'<script[^>]*>.*?</script>', '', response, flags=re.IGNORECASE | re.DOTALL)
        response = re.sub(r'<iframe[^>]*>.*?</iframe>', '', response, flags=re.IGNORECASE | re.DOTALL)

        return response.strip()

    @staticmethod
    def sanitize_sql_string(value: str) -> str:
        """
        Sanitize string for SQL (escape quotes).

        NOTE: Should use parameterized queries instead when possible.

        Args:
            value: String to sanitize

        Returns:
            Sanitized string
        """
        # Escape single quotes
        return value.replace("'", "''").replace("\\", "\\\\")


def validate_websocket_message(message: Dict[str, Any]) -> Dict[str, Any]:
    """
    Validate incoming WebSocket message.

    Args:
        message: Parsed JSON message

    Returns:
        Validated message dict

    Raises:
        ValidationError: If validation fails
    """
    if not isinstance(message, dict):
        raise ValidationError("Message must be a JSON object")

    # Validate type field
    if 'type' not in message:
        raise ValidationError("Message missing 'type' field")

    msg_type = message['type']
    if not isinstance(msg_type, str):
        raise ValidationError("Message type must be a string")

    # Validate based on type
    if msg_type == 'init':
        if 'userID' not in message:
            raise ValidationError("Init message missing 'userID'")
        message['userID'] = Validator.validate_user_id(message['userID'])

    elif msg_type == 'command':
        if 'value' not in message:
            raise ValidationError("Command message missing 'value'")
        message['value'] = Validator.validate_command(message['value'])

    elif msg_type == 'speed':
        if 'value' not in message:
            raise ValidationError("Speed message missing 'value'")
        message['value'] = Validator.validate_speed(message['value'])

    elif msg_type == 'answer':
        if 'id' not in message:
            raise ValidationError("Answer message missing 'id'")
        if 'response' not in message:
            raise ValidationError("Answer message missing 'response'")

        message['id'] = Validator.validate_answer_id(message['id'])
        message['response'] = Validator.validate_response_text(message['response'])

    else:
        # Allow unknown types but log them
        pass

    return message
