# By: Riasat Ullah
# This file will contain validations for http requests made to the api.

from exceptions.user_exceptions import InvalidRequest
from rest_framework.exceptions import ParseError
from taskcallrest import settings
from utils import constants, errors, logging
import configuration


def validate_fields(request, expected_fields, optional_fields=[]):
    '''
    Checks if all required fields have been provided in the http request or not
    :param request: Http request
    :param expected_fields: list of attributes needed to be provided with the request
    :param optional_fields: list of optional attributes
    :errors: InvalidRequest
    '''
    try:
        request_attributes = request.data.keys()
    except ParseError:
        raise InvalidRequest(errors.err_invalid_request)

    # Check if there are duplicate attributes in the request.
    if len(request_attributes) != len(set(request_attributes)):
        logging.error('Duplicate data was sent in the request. Blocking request.')
        raise InvalidRequest(errors.err_invalid_request)

    # Check if any expected fields are missing or not.
    missing_fields = set(expected_fields).difference(set(request_attributes))
    if len(missing_fields) > 0:
        logging.error('The following required fields are missing - ' + str(missing_fields).lstrip('{').rstrip('}'))
        raise InvalidRequest(errors.err_invalid_request)

    # Check if any extra fields provided are part of the optional fields or not.
    extra_fields = set(request_attributes).difference(set(expected_fields))
    if len(extra_fields) > 0:
        if not extra_fields.issubset(set(optional_fields)):
            raise InvalidRequest(errors.err_invalid_request)


def get_user_language(request):
    '''
    Get the language in which the user's contents should be delivered.
    :param request: Http request
    :return: (str) language code
    '''
    if constants.accept_language_attribute in request.headers:
        languages_header = request.headers.get(constants.accept_language_attribute)
        languages = languages_header.split(",")
        locales = []
        for language in languages:
            locale = language.split(';')[0].strip().split('-')[0]
            if locale not in locales:
                locales.append(locale)

        if len(locales) > 0 and locales[0] in configuration.allowed_languages:
            return locales[0]

    return settings.LANGUAGE_CODE


def validate_api_ip_allowed(request, ip_restrictions: list):
    '''
    Checks if a request originated from an IP address not in the list of IP restrictions.
    :param request: Http request
    :param ip_restrictions: (list) of IP restrictions
    :error: PermissionError
    '''
    if ip_restrictions is not None:
        ip_address = request.META.get(constants.ip_address_attribute)
        if ip_address not in ip_restrictions:
            raise PermissionError(errors.err_api_key_request_denied)
