from django import VERSION as DJANGO_VERSION
from django.core.exceptions import ValidationError
from django.http import QueryDict, HttpRequest
from functools import wraps
from eggplant.views.exceptions import LackOfRequiredKeyError, KeyValidationError
from eggplant.views.functions import lack_of_required_key_default_handler, key_validation_failed_default_handler
from eggplant.views import View

def _get_request_data(request):
    if request.method.lower() == 'put':
        if DJANGO_VERSION[1] >= 4:
            raw_request_data = request.body
        else:
            raw_request_data = request.raw_post_data
        requestData = QueryDict(raw_request_data)
    elif request.method.lower() == 'post':
        requestData = request.POST
    else:
        requestData = request.GET

    return requestData

def _get_wrapped_type(args):
    if isinstance(args[0], HttpRequest):
        # Function base
        viewObject = None
        request = args[0]
        is_class_based = False
    elif isinstance(args[0], View):
        # Class base
        viewObject = args[0]
        request = args[0].request
        is_class_based = True
    else:
        viewObject = None
        request = None
        is_class_based = None

    return viewObject, request, is_class_based

def required_keys(*keys, **kwargs):
    error_handler = kwargs.get('error_handler', None)
    if error_handler is None:
        error_handler = lack_of_required_key_default_handler

    def wrapper(fn):
        @wraps(fn)
        def wrapped(*args, **kwargs):
            viewObject, request, is_class_based = _get_wrapped_type(args)
            if request is None:
                return fn(*args, **kwargs)

            requestData = _get_request_data(request)

            for key in keys:
                if key not in requestData:
                    if is_class_based:
                        viewObject.response.content = ''
                        e = LackOfRequiredKeyError(key)
                        e.error_handler = viewObject.lack_of_required_key
                        raise e
                    else:
                        return error_handler(request, key, *args, **kwargs)

            return fn(*args, **kwargs)
        return wrapped

    return wrapper

def validate_keys(*key_validator_pairs, **kwargs):
    error_handler = kwargs.get('error_handler', None)
    if error_handler is None:
        error_handler = key_validation_failed_default_handler

    def wrapper(fn):
        @wraps(fn)
        def wrapped(*args, **kwargs):
            viewObject, request, is_class_based = _get_wrapped_type(args)
            if request is None:
                return fn(*args, **kwargs)

            requestData = _get_request_data(request)

            for key, validator in key_validator_pairs:
                if key in requestData:
                    try:
                        validator(requestData[key])
                    except ValidationError, e:
                        if is_class_based:
                            viewObject.response.content = ''
                            e = KeyValidationError(key, e.messages)
                            e.error_handler = viewObject.key_validation_failed
                            raise e
                        else:
                            return error_handler(request, key, *args, **kwargs)

            return fn(*args, **kwargs)
        return wrapped
    return wrapper