# coding=utf8
from __future__ import unicode_literals

from django.utils.translation import ugettext_lazy as _
from rest_framework import exceptions
from rest_framework.authentication import TokenAuthentication, get_authorization_header
from django.core.cache import cache


class MyTokenAuthentication(TokenAuthentication):
    def authenticate(self, request):
        token = request.GET.get('token')
        if token:
            return self.authenticate_credentials(token)

        auth = get_authorization_header(request).split()

        if not auth or auth[0].lower() != b'token':
            return None

        if len(auth) == 1:
            msg = _('Invalid token header. No credentials provided.')
            raise exceptions.AuthenticationFailed(msg)
        elif len(auth) > 2:
            msg = _('Invalid token header. Token string should not contain spaces.')
            raise exceptions.AuthenticationFailed(msg)

        try:
            token = auth[1].decode()
        except UnicodeError:
            msg = _('Invalid token header. Token string should not contain invalid characters.')
            raise exceptions.AuthenticationFailed(msg)

        return self.authenticate_credentials(token)

    def _get_cache_token(self, key):
        cache_key = 'user_token_%s' % key
        token = cache.get(cache_key, None)
        if token:
            return token.user, token

        try:
            token = self.model.objects.select_related('user').get(key=key)
        except self.model.DoesNotExist:
            raise exceptions.AuthenticationFailed(_('Invalid token.'))

        if not token.user.is_active:
            raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))

        cache.set(cache_key, token, 10 * 60)
        return token.user, token

    def authenticate_credentials(self, key):
        self.model = self.get_model()
        return self._get_cache_token(key)
