from rest_framework_jwt.serializers import (
    JSONWebTokenSerializer as jwt_serializer,
    jwt_payload_handler,
    jwt_encode_handler
)
from rest_framework import serializers
from django.contrib.auth import authenticate as auth
from rest_framework.exceptions import AuthenticationFailed
from django.utils.translation import ugettext as _
from .models import LoginLog
from django.contrib.auth.models import User


def authenticate(request=None, **credentials):
    ip = request._request.META.get('REMOTE_ADDR')
    username = credentials.get('username', None)
    try_user = None
    if username:
        try_user = User.objects.filter(username=username).first()
    if LoginLog.has_locked_out(ip):
        raise AuthenticationFailed('Locked out: too many authentication ' +
                                   'failures. Wait 5 Minutes and try again.')
    new_log = LoginLog.create_log_now(ip, username)
    if try_user:
        new_log.user = try_user
    try:
        user = auth(None, **credentials)
        if user:
            new_log.successful = True
        else:
            new_log.successful = False
        new_log.save()
        return user
    except AuthenticationFailed as e:
        new_log.successful = False
    new_log.save()
    return user


class JSONWebTokenSerializer(jwt_serializer):

    def validate(self, attrs):
        credentials = {
            self.username_field: attrs.get(self.username_field),
            'password': attrs.get('password')
        }

        if all(credentials.values()):
            user = authenticate(
                request=self.context.get('request'),
                **credentials
            )
            if user:
                if not user.is_active:
                    msg = _('User account is disabled.')
                    raise serializers.ValidationError(msg)

                payload = jwt_payload_handler(user)

                return {
                    'token': jwt_encode_handler(payload),
                    'user': user
                }
            else:
                msg = _('Unable to log in with provided credentials.')
                raise serializers.ValidationError(msg)
        else:
            msg = _('Must include "{username_field}" and "password".')
            msg = msg.format(username_field=self.username_field)
            raise serializers.ValidationError(msg)
