"""Common account views"""
from django.conf import settings
from django.utils.encoding import force_text
from django.utils.http import urlsafe_base64_decode
from fcm_django.models import FCMDevice
from rest_framework import generics
from rest_framework import permissions
from rest_framework import status
from rest_framework.response import Response

from account import models
from account.serializers import common as serializers
from authorization.tasks import send_confirm_email
from utils import exceptions as utils_exceptions
from utils.models import GMTokenGenerator
from utils.views import JWTGenericViewMixin


# User views
class UserRetrieveUpdateView(generics.RetrieveUpdateAPIView):
    """User update view."""
    serializer_class = serializers.UserSerializer
    queryset = models.User.objects.active()

    def get_object(self):
        return self.request.user


class ChangePasswordView(generics.GenericAPIView):
    """Change password view"""
    serializer_class = serializers.ChangePasswordSerializer
    queryset = models.User.objects.active()

    def patch(self, request, *args, **kwargs):
        """Implement PUT method"""
        serializer = self.get_serializer(instance=self.request.user,
                                         data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(status=status.HTTP_200_OK)


class SendConfirmationEmailView(generics.GenericAPIView):
    """Confirm email view."""

    def post(self, request, *args, **kwargs):
        """Override create method"""
        user = self.request.user
        country_code = self.request.country_code

        if user.email_confirmed:
            raise utils_exceptions.EmailConfirmedError()

        # Send verification link on user email for change email address
        if settings.USE_CELERY:
            send_confirm_email.delay(
                user_id=user.id,
                country_code=country_code)
        else:
            send_confirm_email(
                user_id=user.id,
                country_code=country_code)
        return Response(status=status.HTTP_200_OK)


class ConfirmEmailView(JWTGenericViewMixin, generics.GenericAPIView):
    """View for confirm changing email"""

    permission_classes = (permissions.AllowAny,)

    def get(self, request, *args, **kwargs):
        """Implement GET-method"""
        uidb64 = kwargs.get('uidb64')
        token = kwargs.get('token')
        uid = force_text(urlsafe_base64_decode(uidb64))
        user_qs = models.User.objects.filter(pk=uid)
        if user_qs.exists():
            user = user_qs.first()
            if not GMTokenGenerator(GMTokenGenerator.CONFIRM_EMAIL).check_token(
                    user, token):
                raise utils_exceptions.NotValidTokenError()
            # Approve email status
            user.confirm_email()
            # 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))
        else:
            raise utils_exceptions.UserNotFoundError()


# Firebase Cloud Messaging
class FCMDeviceViewSet(generics.GenericAPIView):
    """FCMDevice registration view.

    * Pair of fields **registration_id** and **type** should be unique.
    * In case of requested device existance, existing device will be returned
      instead of creating new one.
    """

    serializer_class = serializers.FCMDeviceSerializer
    lookup_fields = ('registration_id', 'type',)
    queryset = FCMDevice.objects.all()
    permission_classes = (permissions.AllowAny,)

    def post(self, request, *args, **kwargs):
        """Override post method."""
        instance = self.get_object_or_none()
        serializer = self.get_serializer(instance, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(
            serializer.data, status=status.HTTP_200_OK if instance else status.HTTP_201_CREATED)

    def get_object_or_none(self):
        """Object as resylt and the view is displaying or None."""
        queryset = self.get_queryset()  # get the base queryset
        queryset = self.filter_queryset(queryset)  # apply any filter backends
        # generate filter
        filter = {f: self.request.data.get(f) for f in self.lookup_fields
                  if self.request.data.get(f)}

        # get object and check permissions or return None
        obj = queryset.filter(**filter).first()
        obj and self.check_object_permissions(self.request, obj)
        return obj
