"""Views to register, edit and view users and/or members including their
profile."""
from datetime import date

from csp.decorators import csp_update
from django import http
from django.conf import settings
from django.contrib import auth, messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse
from django.http import Http404
from django.utils.decorators import method_decorator
from django.utils.translation import ugettext as _
from django.views import generic

from mahjong_ranking.models import KyuDanRanking, SeasonRanking
from . import forms, models

RECAPTCHA_CSP = {
    'SCRIPT_SRC': (
        'https://www.google.com/recaptcha/',
        'https://www.gstatic.com/recaptcha/'
    ),
    'CHILD_SRC': ('https://www.google.com/recaptcha/',)
}


class ActivateRegistration(generic.TemplateView):
    """
    Activates the Registration of an User, log him in and redirect to his
    profile, also display an error message if the activation has failed.
    """
    template_name = 'membership/activation_error.html'

    def get(self, request, *args, **kwargs):
        """fetch the activation key and try to activate it."""
        activation_key = self.kwargs.get('activation_key')
        user = models.ActivationRequest.objects.activate(activation_key)
        if user:
            return self.login(user)
        return super(ActivateRegistration, self).get(
            request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        """Add the acctivation days and the activation key to the template
        context."""
        context = super(ActivateRegistration, self).get_context_data(**kwargs)
        context.update({
            'expiration_days': settings.ACCOUNT_ACTIVATION_DAYS,
            'activation_key': self.kwargs.get('activation_key'),

        })
        return context

    def login(self, user):
        """Log the user in and redirect to his profile."""
        backend = auth.get_backends()[0]
        user.backend = "%s.%s" % (
            backend.__module__, backend.__class__.__name__)
        auth.login(self.request, user)
        messages.success(self.request, _('Activation successful. \
        You can now login anytime with you username and password.'))
        return http.HttpResponseRedirect(
            reverse('membership-edit', args=(user.username,)))


class ActivationSent(generic.TemplateView):
    """Inform a user that a activation request has been send to him."""
    template_name = 'membership/activation_sent.html'


class EditMembership(LoginRequiredMixin, generic.UpdateView):
    """A From that allows Memebers to edit their profile."""
    form_class = forms.MembershipForm

    def get_object(self, queryset=None):
        """If the authenticated user is allowed to change Membership objects,
        fetch the given account. Everybody else only get his own Membeship
        object returned."""
        if self.request.user.has_perm('membership.change_membership'):
            return models.Membership.objects.get(
                username=self.kwargs['username'])
        else:
            return models.Membership.objects.get(username=self.request.user)

    def form_valid(self, form):
        """Add a success message to the message queue."""
        messages.success(self.request, _('User Profile changed successfully'))
        return generic.UpdateView.form_valid(self, form)


class MembershipDetail(LoginRequiredMixin, generic.DetailView):
    """To display the public user profile of an spcific user.
    If no user has been specified, display your own profile.
    """
    model = models.Membership

    def get_object(self, queryset=None):
        """Get the Membership Profile matching the username given in the URI,
        or the current logged in user if no username has been specified.

        :param queryset: the `QuerySet` that will be used to look up the object.
        :return: a Membership Object, or raises a 404 if nothing found.
        """
        queryset = queryset or self.get_queryset()
        try:
            if self.kwargs.get('username'):
                return queryset.get(username=self.kwargs['username'])
            elif self.request.user.is_authenticated():
                return self.request.user
        except models.Membership.DoesNotExist:
            raise Http404(_("No Membership found matching the query"))

    def get_context_data(self, **kwargs):
        """ Add the ladder ranking and the Kyu and Dan ranking the user profile.

        :return: array with the context data
        """
        context = generic.DetailView.get_context_data(self, **kwargs)
        try:
            context['kyu_dan_ranking'] = KyuDanRanking.objects.get(
                user=self.object)
        except KyuDanRanking.DoesNotExist:
            context['kyu_dan_ranking'] = None
        try:
            context['ladder_ranking'] = SeasonRanking.objects.get(
                user=self.object,
                season=date.today().year)
        except SeasonRanking.DoesNotExist:
            context['ladder_ranking'] = SeasonRanking(user=self.object)
        return context


class RegisterForm(generic.FormView):
    """To register a new user on this website. Secured by reCaptcha."""
    form_class = forms.RegistrationForm
    success_url = '/membership/activation_sent/'
    template_name = 'membership/register_form.html'

    @method_decorator(csp_update(**RECAPTCHA_CSP))
    def dispatch(self, request, *args, **kwargs):
        """Overwrite to add googles recaptcha ressoruces to the
        Content-Security_Policity HTTP Headers.
        :param request:
        :param args:
        :param kwargs:
        :return: """
        return super(RegisterForm, self).dispatch(request, *args, **kwargs)

    def form_valid(self, form):
        """Save the formdata and redirect to the success_url. """
        form.save()
        return generic.FormView.form_valid(self, form)
