from functools import wraps

import structlog
from django.conf import settings
from django.contrib.auth.views import redirect_to_login
from django.utils.deprecation import MiddlewareMixin

logger = structlog.get_logger(__name__)


class AuthenticationRequiredMiddleware(MiddlewareMixin):
    def process_view(self, request, callback, callback_args, callback_kwargs):
        if getattr(callback, "authentication_exempt", False):
            return None

        if not request.user.is_authenticated:
            return redirect_to_login(request.build_absolute_uri(), settings.LOGIN_URL)

        return None


def django_view_authentication_exempt(view_func):
    def wrapped_view(*args, **kwargs):
        return view_func(*args, **kwargs)

    wrapped_view.authentication_exempt = True
    return wraps(view_func)(wrapped_view)


class DjangoViewAuthenticationExemptDRFViewMixin:
    @classmethod
    def as_view(cls, **initkwargs):
        view = super(DjangoViewAuthenticationExemptDRFViewMixin, cls).as_view(
            **initkwargs
        )
        view.authentication_exempt = True
        return view


class DjangoViewAuthenticationExemptDRFViewSetMixin:
    @classmethod
    def as_view(cls, actions=None, **initkwargs):
        view = super(DjangoViewAuthenticationExemptDRFViewSetMixin, cls).as_view(
            actions=actions, **initkwargs
        )
        view.authentication_exempt = True
        return view


# https://stackoverflow.com/questions/4898408/how-to-set-a-login-cookie-in-django
class UserLoggedInCookieMiddleWare(MiddlewareMixin):
    """
    Middleware to set user cookie
    If user is authenticated and there is no cookie, set the cookie,
    If the user is not authenticated and the cookie remains, delete it
    """

    cookie_name = "loginStatus"

    def process_response(self, request, response):
        # if user and no cookie, set cookie
        if request.user.is_authenticated and not request.COOKIES.get(self.cookie_name):
            response.set_cookie(self.cookie_name, "true")
        elif not request.user.is_authenticated and request.COOKIES.get(
            self.cookie_name
        ):
            # else if no user and cookie remove user cookie, logout
            response.delete_cookie(self.cookie_name)
        return response
