from django.contrib.auth import get_user_model
from django.core.exceptions import PermissionDenied

from kfet.models import Account, GenericTeamToken

from .utils import get_kfet_generic_user

User = get_user_model()


class BaseKFetBackend:
    def get_user(self, user_id):
        """
        Add extra select related up to Account.
        """
        try:
            return User.objects.select_related("profile__account_kfet").get(pk=user_id)
        except User.DoesNotExist:
            return None


class AccountBackend(BaseKFetBackend):
    def authenticate(self, request, kfet_password=None):
        try:
            return Account.objects.get_by_password(kfet_password).user
        except Account.DoesNotExist:
            return None


class GenericBackend(BaseKFetBackend):
    def authenticate(self, request, kfet_token=None):
        try:
            team_token = GenericTeamToken.objects.get(token=kfet_token)
        except GenericTeamToken.DoesNotExist:
            return

        # No need to keep the token.
        team_token.delete()

        return get_kfet_generic_user()


class BlockFrozenAccountBackend:
    def authenticate(self, request, **kwargs):
        return None

    def get_user(self, user_id):
        return None

    def has_perm(self, user_obj, perm, obj=None):
        app_label, _ = perm.split(".")
        if app_label == "kfet":
            if (
                hasattr(user_obj, "profile")
                and hasattr(user_obj.profile, "account_kfet")
                and user_obj.profile.account_kfet.is_frozen
            ):
                raise PermissionDenied

        # Dans le cas général, on se réfère aux autres backends
        return False

    def has_module_perms(self, user_obj, app_label):
        if app_label == "kfet":
            if (
                hasattr(user_obj, "profile")
                and hasattr(user_obj.profile, "account_kfet")
                and user_obj.profile.account_kfet.is_frozen
            ):
                raise PermissionDenied

        # Dans le cas général, on se réfère aux autres backends
        return False
