from urllib.parse import urlparse, urlunparse

from django.conf import settings
from django.contrib import auth
from django.contrib.auth import views as auth_views
from django.core.exceptions import PermissionDenied
from django.shortcuts import redirect
from django.utils.translation import gettext_lazy as _
from django.views.generic import TemplateView, View

from .forms import ElectionAuthForm
from .utils import get_cas_client


class NextPageMixin:
    def get_next_url(self):
        """Decide where to go after a successful login.

        Look for (in order):
        - a `next` GET parameter;
        - a `CASNEXT` session variable;
        - the `LOGIN_REDIRECT_URL` django setting.
        """
        request = self.request
        next_url = request.GET.get("next")
        if next_url is None and "CASNEXT" in request.session:
            next_url = request.session["CASNEXT"]
            del request.session["CASNEXT"]
        if next_url is None:
            next_url = settings.LOGIN_REDIRECT_URL
        return next_url


class LoginSelectView(NextPageMixin, TemplateView):
    """Simple page letting the user choose between password and CAS authentication."""

    template_name = "auth/login_select.html"
    http_method_names = ["get"]

    def get(self, request, *args, **kwargs):
        if request.user.is_authenticated:
            return redirect(self.get_next_url())
        return super().get(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["next"] = self.get_next_url()
        context["method"] = self.request.GET.get("method", "CAS")
        context["election_id"] = self.request.GET.get("election_id", None)

        return context


class CASLoginView(NextPageMixin, View):
    """CAS authentication view.

    Implement the CAS authentication scheme:

    1. We first redirect the user to the student CAS.
    2. The user comes back with a ticket, we validate it to make sure the user is legit
       (validation is delegated to the ENSCASBackend).
    3. We redirect the user to the next page.
    """

    http_method_names = ["get"]

    def get(self, request, *args, **kwargs):
        ticket = request.GET.get("ticket")

        if not ticket:
            request.session["CASNEXT"] = self.get_next_url()
            cas_client = get_cas_client(request)
            return redirect(cas_client.get_login_url())

        user = auth.authenticate(request, ticket=ticket)
        if user is None:
            raise PermissionDenied(_("Connexion échouée !"))
        auth.login(request, user)
        return redirect(self.get_next_url())


class PasswordLoginView(auth_views.LoginView):
    template_name = "auth/pwd_login.html"
    authentication_form = ElectionAuthForm

    def get_initial(self):
        return {"election_id": self.request.GET.get("election_id", None)}


class LogoutView(auth_views.LogoutView):
    """Logout view.

    Tell Django to log the user out, then redirect to the CAS logout page if the user
    logged in via CAS.
    """

    template_name = "auth/logout.html"

    def setup(self, request):
        super().setup(request)
        if "CASCONNECTED" in request.session:
            del request.session["CASCONNECTED"]
            self.cas_connected = True
        else:
            self.cas_connected = False

    def get_next_page(self):
        next_page = super().get_next_page()
        if self.cas_connected:
            cas_client = get_cas_client(self.request)

            # If the next_url is local (no hostname), make it absolute so that the user
            # is correctly redirected from CAS.
            if not urlparse(next_page).netloc:
                request = self.request
                next_page = urlunparse(
                    (request.scheme, request.get_host(), next_page, "", "", "")
                )

            next_page = cas_client.get_logout_url(redirect_url=next_page)
        return next_page
