import datetime

from django.db import models
from django.views import generic
from django.utils.text import slugify

from .models import Mandate, Group


class RepresentativeViewMixin(object):
    """
    A view mixin to add pre-fetched main_mandate and country to Representative

    If a Representative was fetched from a QuerySet that have been through
    prefetch_for_representative_country_and_main_mandate(), then
    add_representative_country_and_main_mandate(representative) adds the
    ``.country`` and ``.main_mandate`` properties "for free" - the prefetch
    methods adds an extra query, but gets all.
    """

    def prefetch_for_representative_country_and_main_mandate(self, queryset):
        """
        Prefetch Mandates with their Group and Constituency with Country.
        """
        mandates = Mandate.objects.order_by(
            '-end_date').select_related('constituency__country', 'group',
            'group__chamber')
        return queryset.prefetch_related(
            models.Prefetch('mandates', queryset=mandates))

    def add_representative_country_and_main_mandate(self, representative):
        """
        Set representative country, main_mandate and chamber.

        Note that this will butcher your database if you don't use
        self.prefetch_related.
        """
        today = datetime.date.today()

        representative.country = None
        representative.main_mandate = None

        for m in representative.mandates.all():
            if m.constituency.country_id and not representative.country:
                representative.country = m.constituency.country

            if ((m.end_date is None or m.end_date > today) and
                    m.group.kind == 'group' and
                    not representative.main_mandate):

                representative.main_mandate = m

            if representative.country and representative.main_mandate:
                break

        if representative.main_mandate:
            representative.chamber = representative.main_mandate.group.chamber

        return representative


class RepresentativeList(RepresentativeViewMixin, generic.ListView):
    def get_context_data(self, **kwargs):
        c = super(RepresentativeList, self).get_context_data(**kwargs)

        c['object_list'] = [
            self.add_representative_country_and_main_mandate(r)
            for r in c['object_list']
        ]

        return c

    def search_filter(self, qs):
        search = self.request.GET.get('search', None)
        if search:
            qs = qs.filter(slug__icontains=slugify(search))
        return qs

    def group_filter(self, qs):
        group_kind = self.kwargs.get('group_kind', None)
        chamber = self.kwargs.get('chamber', None)
        group = self.kwargs.get('group', None)
        today = datetime.date.today()

        if group_kind and group:
            if group.isnumeric():
                group_qs = Group.objects.filter(
                    id=int(group)
                )
            else:
                group_qs = Group.objects.filter(
                    name=group,
                    kind=group_kind
                )

            if chamber:
                group_qs = group_qs.filter(chamber__name=chamber)

            qs = qs.filter(
                models.Q(mandates__end_date__gte=today) |
                models.Q(mandates__end_date__isnull=True),
                mandates__group__in=group_qs
            )

        return qs

    def get_queryset(self):
        qs = super(RepresentativeList, self).get_queryset()
        qs = self.group_filter(qs)
        qs = self.search_filter(qs)
        qs = self.prefetch_for_representative_country_and_main_mandate(qs)
        return qs


class RepresentativeDetail(RepresentativeViewMixin, generic.DetailView):
    def get_queryset(self):
        qs = super(RepresentativeDetail, self).get_queryset()
        qs = self.prefetch_for_representative_country_and_main_mandate(qs)
        return qs

    def get_context_data(self, **kwargs):
        c = super(RepresentativeDetail, self).get_context_data(**kwargs)

        self.add_representative_country_and_main_mandate(c['object'])

        c['votes'] = c['object'].votes.all()
        c['mandates'] = c['object'].mandates.all()
        c['positions'] = c['object'].positions.filter(
            published=True).prefetch_related('tags')

        return c


class GroupList(generic.ListView):
    def get_queryset(self):
        qs = Group.objects.filter(
            models.Q(mandates__end_date__gte=datetime.date.today()) |
            models.Q(mandates__end_date__isnull=True)
        )

        kind = self.kwargs.get('kind', None)
        if kind:
            qs = qs.filter(kind=kind).distinct()

        return qs.select_related('chamber').order_by('chamber__name', 'name')