from django.db.models import Q
from django.http import JsonResponse


def is_datatables_request(request):
    return request.GET.get('draw') is not None


def parse_datatables_request(request, default_length=10):
    try:
        draw = int(request.GET.get('draw', 1))
    except (TypeError, ValueError):
        draw = 1
    try:
        start = max(int(request.GET.get('start', 0)), 0)
    except (TypeError, ValueError):
        start = 0
    try:
        length = int(request.GET.get('length', default_length))
    except (TypeError, ValueError):
        length = default_length
    if length < 1:
        length = default_length
    if length > 100:
        length = 100
    search = (request.GET.get('search[value]', '') or '').strip()
    return draw, start, length, search


def apply_datatables_search(qs, search, fields):
    if not search or not fields:
        return qs
    query = Q()
    for field in fields:
        query |= Q(**{f'{field}__icontains': search})
    return qs.filter(query)


def apply_datatables_order(request, order_fields, default_order):
    order_col_idx = request.GET.get('order[0][column]')
    order_dir = request.GET.get('order[0][dir]', 'asc')
    if order_col_idx is not None:
        try:
            idx = int(order_col_idx)
            if 0 <= idx < len(order_fields):
                field = order_fields[idx]
                if field:
                    if order_dir == 'desc':
                        return [f'-{field.lstrip("-")}']
                    return [field.lstrip('-')]
        except (TypeError, ValueError):
            pass
    return list(default_order)


def datatables_response(draw, records_total, records_filtered, data):
    return JsonResponse({
        'draw': draw,
        'recordsTotal': records_total,
        'recordsFiltered': records_filtered,
        'data': data,
    })


def paginate_datatables_queryset(request, queryset, serializer, search_fields, order_fields, default_order):
    draw, start, length, search = parse_datatables_request(request)
    records_total = queryset.count()
    filtered_qs = apply_datatables_search(queryset, search, search_fields)
    records_filtered = filtered_qs.count()
    ordered_qs = filtered_qs.order_by(
        *apply_datatables_order(request, order_fields, default_order),
    )
    page = ordered_qs[start:start + length]
    return datatables_response(
        draw,
        records_total,
        records_filtered,
        [serializer(item) for item in page],
    )
