from django.contrib.auth import authenticate, get_user_model
from django.contrib.auth.models import update_last_login
from django.db.models import F
from rest_framework_simplejwt.serializers import (
    TokenObtainPairSerializer,
    TokenObtainSerializer,
)
from rest_framework_simplejwt.settings import api_settings
from verify_trusted.users.models import *

User = get_user_model()


class UserTokenObtainSerializer(TokenObtainSerializer):
    def validate(self, attrs):
        authenticate_kwargs = {
            self.username_field: attrs[self.username_field],
            'password': attrs['password'],
        }
        try:
            authenticate_kwargs['request'] = self.context['request']
        except KeyError:
            pass

        self.user = authenticate(**authenticate_kwargs)
        get_user = None
        if self.user is None:
            get_user = User.objects.filter(username=attrs[self.username_field])
            if get_user is not None:
                get_user.update(fail_to_login=F('fail_to_login') + 1)

        else:
            self.user.fail_to_login = 0
            self.user.save()
            profile = Profile.objects.filter(user=self.user).first()
            if not profile.connect_token:
                profile.connect_token = str(uuid.uuid4())
                profile.save()

        if not api_settings.USER_AUTHENTICATION_RULE(self.user):
            return {
                "fail_login": get_user[0].fail_to_login if len(get_user) > 0 else 0,
                "detail": "MSG018",
            }

        return {}


class UserTokenObtainPairSerializer(TokenObtainPairSerializer):
    # https://stackoverflow.com/a/62113588
    def validate(self, attrs):
        userToken = UserTokenObtainSerializer()
        # The default result (access/refresh tokens)
        data = userToken.validate(attrs)

        if len(data) > 0:
            return data
        refresh = self.get_token(userToken.user)

        data['refresh'] = str(refresh)
        data['access'] = str(refresh.access_token)

        if api_settings.UPDATE_LAST_LOGIN:
            update_last_login(None, userToken.user)
        return data

    @classmethod
    def get_token(cls, user: User):
        token = super().get_token(user)

        # Add custom claims
        user_claims = {
            'id': user.id,
            'name': user.name,
            'username': user.username,
            'email': user.email,
            'is_superuser': user.is_superuser,
            # TODO: ita & eta
        }
        token['user'] = user_claims

        return token

    class Meta:
        extra_kwargs = {
            'email': {
                'trim_whitespace': True,
            },
        }
