"""Web account views"""
from django.conf import settings
from django.db import transaction
from django.shortcuts import get_object_or_404
from django.utils.encoding import force_text
from django.utils.http import urlsafe_base64_decode
from rest_framework import permissions, status, generics
from rest_framework.response import Response

from account import tasks, models
from account.serializers import web as serializers
from utils import exceptions as utils_exceptions
from utils.models import GMTokenGenerator
from utils.views import JWTGenericViewMixin


class PasswordResetView(generics.GenericAPIView):
    """View for resetting user password"""
    permission_classes = (permissions.AllowAny, )
    serializer_class = serializers.PasswordResetSerializer

    def post(self, request, *args, **kwargs):
        """Override create method"""
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        if not serializer.validated_data.get('user').is_anonymous:
            user = serializer.validated_data.pop('user')
            if settings.USE_CELERY:
                tasks.send_reset_password_email.delay(user_id=user.id,
                                                      country_code=self.request.country_code)
            else:
                tasks.send_reset_password_email(user_id=user.id,
                                                country_code=self.request.country_code)
        return Response(status=status.HTTP_200_OK)


class PasswordResetConfirmView(JWTGenericViewMixin, generics.GenericAPIView):
    """View for confirmation new password"""
    serializer_class = serializers.PasswordResetConfirmSerializer
    permission_classes = (permissions.AllowAny,)
    queryset = models.User.objects.active()

    def get_object(self):
        """Overridden get_object method"""
        queryset = self.filter_queryset(self.get_queryset())
        uidb64 = self.kwargs.get('uidb64')

        user_id = force_text(urlsafe_base64_decode(uidb64))
        token = self.kwargs.get('token')

        user = get_object_or_404(queryset, id=user_id)

        if not GMTokenGenerator(GMTokenGenerator.RESET_PASSWORD).check_token(
                user, token):
            raise utils_exceptions.NotValidTokenError()

        # May raise a permission denied
        self.check_object_permissions(self.request, user)

        return user

    def patch(self, request, *args, **kwargs):
        """Implement PATCH method"""
        instance = self.get_object()
        with transaction.atomic():
            serializer = self.get_serializer(instance=instance,
                                             data=request.data)
            serializer.is_valid(raise_exception=True)
            serializer.save()

            #  apply requested user_role if 'role' in query_params
            if 'role' in request.query_params:
                user_role = get_object_or_404(klass=models.UserRole, pk=request.query_params['role'])
                user_role.state = models.UserRole.VALIDATED
                user_role.save()

        # Create tokens
        tokens = instance.create_jwt_tokens()
        return self._put_cookies_in_response(
            cookies=self._put_data_in_cookies(
                access_token=tokens.get('access_token'),
                refresh_token=tokens.get('refresh_token')),
            response=Response(status=status.HTTP_200_OK))


class ApplyUserEstablishmentRole(JWTGenericViewMixin, generics.GenericAPIView):

    queryset = models.User.objects.all()
    permission_classes = (permissions.AllowAny,)

    def get_object(self):
        """Overridden get_object method"""
        queryset = self.filter_queryset(self.get_queryset())
        uidb64 = self.kwargs.get('uidb64')

        user_id = force_text(urlsafe_base64_decode(uidb64))
        token = self.kwargs.get('token')

        user = get_object_or_404(queryset, id=user_id)

        if not GMTokenGenerator(GMTokenGenerator.RESET_PASSWORD).check_token(
                user, token):
            raise utils_exceptions.NotValidTokenError()

        # May raise a permission denied
        self.check_object_permissions(self.request, user)

        return get_object_or_404(klass=models.UserRole, pk=self.kwargs['role_id'], user=user), user

    def patch(self, request, *args, **kwargs):
        instance, user = self.get_object()
        instance.state = models.UserRole.VALIDATED
        instance.save()
        # Create tokens
        tokens = user.create_jwt_tokens()
        return self._put_cookies_in_response(
            cookies=self._put_data_in_cookies(
                access_token=tokens.get('access_token'),
                refresh_token=tokens.get('refresh_token')),
            response=Response(status=status.HTTP_200_OK))
