from django.db.models import Q, QuerySet
from management.models import FilterAndSorting
from management.utils.error_handling import GenericError

query_operations_map={
    'eq':'',
    '=':'',
    'ex':'__iexact',
    'lk':'__icontains',
    'contains':'__icontains',
    'notcontains':'__icontains',
    'nlk': '__icontains',
    '<>': '__icontains',
    'slk':'__istartswith',
    'startswith':'__istartswith',
    'elk':'__iendswith',
    'endswith':'__iendswith',
    'in':'__in',
    'gt':'__gt',
    'gte':'__gte',
    'lt':'__lt',
    'lte':'__lte',
}

query_operations_not_map={
    'ne':'',
    'nex':'__iexact',
    # 'nlk':'__icontains',
    'nslk':'__istartswith',
    'nelk':'__iendswith',
    'nin':'__in',
    'ngt':'__gt',
    'ngte':'__gte',
    'nlt':'__lte'
}

sorting_operations_map={
    'ASC':'',
    'DESC':'-'
}

def parse_filters_and_sortings(obj: FilterAndSorting, query_set: QuerySet, user_id):
    filter_objects = Q()
    for data in obj.filters:
        if data.field_name == "author" and user_id is not None:
            if user_id != data.filter_value:
                raise GenericError(
                    {"code": "401", "description": "UNAUTHORIZED"}, 401
                )

        filter_objects &= _get_filter(
            data.field_name,
            data.filter_condition,
            data.filter_value
        )

    if obj.filters:
        query_set = query_set.filter(filter_objects)

    orderbyList = [
        f"{sorting_operations_map.get(data.operation)}{data.field_name}"
        for data in obj.sortings
    ]

    return query_set.order_by(*orderbyList)

def _get_filter(field_name, filter_condition, filter_value):
    
    if filter_condition in query_operations_map.keys():
        if  filter_condition.startswith('n') or filter_condition.startswith('<'):  # se è un filtro "not"
            kwargs = {
            '{0}{1}'.format(field_name,query_operations_map.get(filter_condition)): filter_value
            }
            return ~Q(**kwargs)
        else:
            kwargs = {
            '{0}{1}'.format(field_name,query_operations_map.get(filter_condition)): filter_value
            }
            return Q(**kwargs)
       
    
    elif filter_condition in query_operations_not_map.keys():
        raise GenericError({"code": "bad_request",
                         "description":
                         "Unsupported operation type in this web app."},400)
    
    