import logging

from django.views.generic import FormView
from django.contrib import messages
from django.contrib.auth import get_user_model, REDIRECT_FIELD_NAME, authenticate
from django.utils.translation import ugettext as _
from django.utils.http import urlsafe_base64_decode

from .compat import default_token_generator
from .registration_backend.forms import SetPasswordForm
from . import cbv, profile_forms, utils, hooks


class PasswordResetView(cbv.NextURLViewMixin, FormView):
    '''Ask for an email and send a password reset link by mail'''
    form_class = profile_forms.PasswordResetForm
    title = _('Password Reset')

    def get_template_names(self):
        return [
            'authentic2/password_reset_form.html',
            'registration/password_reset_form.html',
        ]

    def get_form_kwargs(self, **kwargs):
        kwargs = super(PasswordResetView, self).get_form_kwargs(**kwargs)
        initial = kwargs.setdefault('initial', {})
        initial['next_url'] = self.request.GET.get(REDIRECT_FIELD_NAME, '')
        return kwargs

    def get_context_data(self, **kwargs):
        ctx = super(PasswordResetView, self).get_context_data(**kwargs)
        ctx['title'] = _('Password reset')
        return ctx

    def form_valid(self, form):
        form.save()
        # return to next URL
        messages.info(self.request, _('If your email address exists in our '
                                      'database, you will receive an email '
                                      'containing instructions to reset '
                                      'your password'))
        return super(PasswordResetView, self).form_valid(form)

password_reset = PasswordResetView.as_view()


class PasswordResetConfirmView(cbv.RedirectToNextURLViewMixin, FormView):
    '''Validate password reset link, show a set password form and login
       the user.
    '''
    form_class = SetPasswordForm
    title = _('Password Reset')

    def get_template_names(self):
        return [
            'registration/password_reset_confirm.html',
            'authentic2/password_reset_confirm.html',
        ]

    def dispatch(self, request, *args, **kwargs):
        validlink = True
        uidb64 = kwargs['uidb64']
        self.token = token = kwargs['token']

        UserModel = get_user_model()
        # checked by URLconf
        assert uidb64 is not None and token is not None
        try:
            uid = urlsafe_base64_decode(uidb64)
            # use authenticate to eventually get an LDAPUser
            self.user = authenticate(user=UserModel._default_manager.get(pk=uid))
        except (TypeError, ValueError, OverflowError,
                UserModel.DoesNotExist):
            validlink = False
            messages.warning(request, _('User not found'))

        if validlink and not default_token_generator.check_token(self.user, token):
            validlink = False
            messages.warning(request, _('You reset password link is invalid '
                                        'or has expired'))
        if not validlink:
            return utils.redirect(request, self.get_success_url())
        can_reset_password = utils.get_user_flag(user=self.user,
                                                 name='can_reset_password',
                                                 default=self.user.has_usable_password())
        if not can_reset_password:
            messages.warning(request, _('It\'s not possible to reset your password. Please '
                                        'contact an administrator.'))
            return utils.redirect(request, self.get_success_url())
        return super(PasswordResetConfirmView, self).dispatch(request, *args,
                                                              **kwargs)

    def get_context_data(self, **kwargs):
        ctx = super(PasswordResetConfirmView, self).get_context_data(**kwargs)
        # compatibility with existing templates !
        ctx['title'] = _('Enter new password')
        ctx['validlink'] = True
        return ctx

    def get_form_kwargs(self):
        kwargs = super(PasswordResetConfirmView, self).get_form_kwargs()
        kwargs['user'] = self.user
        return kwargs

    def form_valid(self, form):
        # Changing password by mail validate the email
        form.user.email_verified = True
        form.save()
        hooks.call_hooks('event', name='password-reset-confirm', user=form.user, token=self.token,
                         form=form)
        logging.getLogger(__name__).info(u'user %s resetted its password with '
                                         'token %r...', self.user,
                                         self.token[:9])
        return self.finish()

    def finish(self):
        return utils.simulate_authentication(self.request, self.user, 'email')

password_reset_confirm = PasswordResetConfirmView.as_view()


def switch_back(request):
    return utils.switch_back(request)
