from django.db.models import Q
from django.http import Http404, HttpResponse
from django.db.models import FieldDoesNotExist

from json import dumps

from staff.django_api_auth.decorators import check_referer
from staff.groups.models import Group, GROUP_TYPE_CHOICES

from staff.apicenter.api_v1 import _default_group_fields
from staff.apicenter.utils import get_fields


def serialize_model(obj, relations=None, fields=None):
    if not relations:
        relations = {}

    if not fields:
        fields = [field.name for field in obj.__class__._meta.fields]

    def field_value(field):
        value = getattr(obj, field.name)

        if field.rel and value and field.name in relations:
            if type(relations[field.name]) == dict and '_fields' in relations[field.name]:
                fields = relations[field.name].get('_fields', None)
            else:
                fields = None

            return serialize_model(value, relations[field.name], fields)

        return str(value) if value is not None else ''

    def generate():
        for field in fields:
            try:
                field = obj.__class__._meta.get_field(field)
            except FieldDoesNotExist:
                if hasattr(obj, field):
                    yield field, getattr(obj, field)
            else:
                yield field.name, field_value(field)

    return dict(generate())


def serialize_models_list(lst, relations=None, fields=None):
    return [serialize_model(item, relations, fields) for item in lst]


class GroupsAutocomplete(object):

    @check_referer
    def __call__(self, request):
        req_data = request.GET or request.POST
        q = req_data.get('q', None)
        if not q:
            raise Http404
        try:
            limit = int(req_data['limit'])
        except (TypeError, KeyError):
            limit = 10
        fields = get_fields(request, _default_group_fields)
        typ = req_data.getlist('type')

        qs = Group.objects.filter(Q(name__icontains=q) | Q(url__icontains=q))\
                          .filter(level__gt=0)

        if not typ or len(typ) == 1:
            qs = qs.filter(self._get_query(typ[0] if len(typ) == 1 else ''))

        elif hasattr(typ, '__iter__'):
            qu = None
            for t in typ:
                if qu is None:
                    qu = self._get_query(t)
                else:
                    qu |= self._get_query(t)
            qs = qs.filter(qu)

        r = []
        for group in qs.filter(intranet_status__gt=0).order_by('level', 'service_id', 'department')[:limit]:
            t = serialize_model(group, None, fields)
            if typ != ['intra']:
                t['ancestors'] = serialize_models_list(group.get_ancestors()[1:], None, ('id', 'name',))
            r.append(t)
        r = dumps(r)

        callback = request.GET.get('callback', request.POST.get('callback', None))
        if callback:
            r = 'var data = %s; %s(data);' % (r, callback)
        return HttpResponse(r, content_type='text/javascript')

    def _get_query(self, typ):
        if typ == 'departments':
            return Q(type=GROUP_TYPE_CHOICES.DEPARTMENT)
        elif typ == 'services':
            return Q(type=GROUP_TYPE_CHOICES.SERVICE)
        elif typ == 'intra':
            return Q(type=GROUP_TYPE_CHOICES.WIKI)
        else:
            return (
                Q(type=GROUP_TYPE_CHOICES.DEPARTMENT) |
                Q(type=GROUP_TYPE_CHOICES.SERVICE) |
                Q(type=GROUP_TYPE_CHOICES.WIKI) |
                Q(type=GROUP_TYPE_CHOICES.SERVICEROLE)
            )
