# authentic2 - versatile identity manager
# Copyright (C) 2010-2019 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.forms import Form
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt, ensure_csrf_cookie

from . import hooks
from .utils import misc as utils_misc
from .utils.views import csrf_token_check


class ValidateCSRFMixin:
    """Move CSRF token validation inside the form validation.

    This mixin must always be the leftest one and if your class override
    form_valid() dispatch() you should move those overrides in a base
    class.
    """

    @method_decorator(csrf_exempt)
    @method_decorator(ensure_csrf_cookie)
    def dispatch(self, *args, **kwargs):
        return super().dispatch(*args, **kwargs)

    def form_valid(self, *args, **kwargs):
        for form in args:
            if isinstance(form, Form):
                csrf_token_check(self.request, form)
        if not form.is_valid():
            return self.form_invalid(form)
        return super().form_valid(*args, **kwargs)


class RedirectToNextURLViewMixin:
    def get_success_url(self):
        if REDIRECT_FIELD_NAME in self.request.GET:
            return self.request.GET[REDIRECT_FIELD_NAME]
        return settings.LOGIN_REDIRECT_URL


class NextURLViewMixin(RedirectToNextURLViewMixin):
    """Make a view handle a next parameter, if it's not present it is
    automatically generated from the Referrer or from the value
    returned by the method get_next_url_default().
    """

    next_url_default = '..'

    def get_next_url_default(self):
        return self.next_url_default

    def dispatch(self, request, *args, **kwargs):
        if REDIRECT_FIELD_NAME in request.GET:
            pass
        else:
            next_url = request.META.get('HTTP_REFERER') or self.next_url_default
            return utils_misc.redirect(
                request,
                request.path,
                keep_params=True,
                params={
                    REDIRECT_FIELD_NAME: next_url,
                },
                status=303,
            )
        return super().dispatch(request, *args, **kwargs)


class TemplateNamesMixin:
    def get_template_names(self):
        if hasattr(self, 'template_names'):
            return self.template_names
        return super().get_template_names()


class HookMixin:
    def get_form(self):
        form = super().get_form()
        hooks.call_hooks('front_modify_form', self, form)
        return form
