from django.conf import settings
from django.db.models import Q
from django.http import Http404
from django.shortcuts import render
from ldap3 import Connection

from gestioncof.models import User
from kfet.decorators import teamkfet_required
from kfet.models import Account


class Clipper(object):
    def __init__(self, clipper, fullname):
        if fullname is None:
            fullname = ""
        assert isinstance(clipper, str)
        assert isinstance(fullname, str)
        self.clipper = clipper
        self.fullname = fullname


@teamkfet_required
def account_create(request):
    if "q" not in request.GET:
        raise Http404
    q = request.GET.get("q")

    if len(q) == 0:
        return render(request, "kfet/account_create_autocomplete.html")

    data = {"q": q}

    queries = {}
    search_words = q.split()

    # Fetching data from User, CofProfile and Account tables
    queries["kfet"] = Account.objects
    queries["users_cof"] = User.objects.filter(profile__is_cof=True)
    queries["users_notcof"] = User.objects.filter(profile__is_cof=False)

    for word in search_words:
        queries["kfet"] = queries["kfet"].filter(
            Q(cofprofile__user__username__icontains=word)
            | Q(cofprofile__user__first_name__icontains=word)
            | Q(cofprofile__user__last_name__icontains=word)
        )
        queries["users_cof"] = queries["users_cof"].filter(
            Q(username__icontains=word)
            | Q(first_name__icontains=word)
            | Q(last_name__icontains=word)
        )
        queries["users_notcof"] = queries["users_notcof"].filter(
            Q(username__icontains=word)
            | Q(first_name__icontains=word)
            | Q(last_name__icontains=word)
        )

    # Clearing redundancies
    queries["kfet"] = queries["kfet"].distinct()
    usernames = set(
        queries["kfet"].values_list("cofprofile__user__username", flat=True)
    )
    queries["kfet"] = [
        (account, account.cofprofile.user) for account in queries["kfet"]
    ]

    queries["users_cof"] = (
        queries["users_cof"].exclude(username__in=usernames).distinct()
    )
    queries["users_notcof"] = (
        queries["users_notcof"].exclude(username__in=usernames).distinct()
    )
    usernames |= set(queries["users_cof"].values_list("username", flat=True))
    usernames |= set(queries["users_notcof"].values_list("username", flat=True))

    # Fetching data from the SPI
    if getattr(settings, "LDAP_SERVER_URL", None):
        # Fetching
        ldap_query = "(&{:s})".format(
            "".join(
                "(|(cn=*{bit:s}*)(uid=*{bit:s}*))".format(bit=word)
                for word in search_words
                if word.isalnum()
            )
        )
        if ldap_query != "(&)":
            # If none of the bits were legal, we do not perform the query
            entries = None
            with Connection(settings.LDAP_SERVER_URL) as conn:
                conn.search("dc=spi,dc=ens,dc=fr", ldap_query, attributes=["uid", "cn"])
                entries = conn.entries
            # Clearing redundancies
            queries["clippers"] = [
                Clipper(entry.uid.value, entry.cn.value)
                for entry in entries
                if entry.uid.value and entry.uid.value not in usernames
            ]

    # Resulting data
    data.update(queries)
    data["options"] = sum([len(query) for query in queries])

    return render(request, "kfet/account_create_autocomplete.html", data)


@teamkfet_required
def account_search(request):
    if "q" not in request.GET:
        raise Http404
    q = request.GET.get("q")
    words = q.split()

    data = {"q": q}

    for word in words:
        query = Account.objects.filter(
            Q(cofprofile__user__username__icontains=word)
            | Q(cofprofile__user__first_name__icontains=word)
            | Q(cofprofile__user__last_name__icontains=word)
        ).distinct()

    query = [
        (account.trigramme, account.cofprofile.user.get_full_name())
        for account in query
    ]

    data["accounts"] = query
    return render(request, "kfet/account_search_autocomplete.html", data)