from django.contrib.auth.hashers import check_password
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from rest_framework.exceptions import ValidationError

from core import serializers
from users.models import UserInfo
from users.services.userinfo import UserStatusService
from users.services.validators import timezone_validation, password_validation, validate_expire_date, \
    OnlyCharNumericValidator

"""The presence of 2 duplicate serilizers (UsersListSerializer,UserInfoListSerializer) 
is made for the quick release of functionality. The reason is hiding the password from the output 
of the list of users"""


class UserSerializers(serializers.ModelSerializer):
    username = serializers.CharField(),
    old_password = serializers.CharField(required=False)

    def to_representation(self, instance):
        return {
            'id': instance.id,
            'username': instance.username,
            'first_name': instance.first_name,
            "email": instance.email,
            'is_active': instance.is_active
        }

    class Meta:
        model = User
        fields = ('id', 'username', 'first_name', 'is_active', "password", "email", "old_password")
        extra_kwargs = {
            'username': {
                'validators': [],
                'max_length': 131  # 150 chars in the model, but after deleting we added 19 chars
            },
            'first_name': {
                'required': True,
                'allow_blank': False
            },
            'email': {
                'required': True,
                'allow_blank': False
            }
        }


class UserInfoSerializer(serializers.ModelLocalizedSerializer):
    user = UserSerializers(required=True, many=False)
    user_status = serializers.SerializerMethodField()

    def get_user_status(self, user_info: UserInfo) -> str:
        return UserStatusService(user_info.user).get_status()

    def create(self, validated_data):
        """TODO !!! Important !!!! Until the role model is developed, all created users are admins"""
        if "password" in validated_data["user"]:
            from django.contrib.auth.hashers import make_password
            validated_data["user"]["password"] = make_password(validated_data["user"]["password"])
            validated_data["user"]["is_staff"] = True
            validated_data["user"]["is_superuser"] = True
            new_user = User.objects.create(**validated_data["user"])
        else:
            new_user = User.objects.create(**validated_data["user"])
        user_info = None
        if new_user:
            user_info = UserInfo.objects.create(user=new_user, comment=validated_data.get("comment"),
                                                timezone=validated_data.get("timezone"),
                                                expire_date=validated_data.get('expire_date'))
        return user_info

    def validate_user(self, user):
        username = user['username']
        OnlyCharNumericValidator.validate(username)
        try:
            user = User.objects.get(username=username)
            raise ValidationError(f"User {username} already exists")
        except ObjectDoesNotExist:
            return user

    def validate(self, data):
        timezone_validation(data)
        password_validation(data)
        validate_expire_date(data)
        return data

    class Meta:
        model = UserInfo
        fields = "__all__"


class UserInfoUpdateSerializer(serializers.ModelLocalizedSerializer):
    user = UserSerializers(required=False)

    def update(self, instance, validated_data):
        try:
            users_data = validated_data.pop('user')
            instance.comment = validated_data.get('comment', instance.comment)
            instance.timezone = validated_data.get("timezone", instance.timezone)
            instance.expire_date = validated_data.get("expire_date", instance.expire_date)
            instance.save()
            user = instance.user
            user.username = users_data.get('username', user.username)
            user.first_name = users_data.get("first_name", user.first_name)
            user.is_active = users_data.get("is_active", user.is_active)
            user.email = users_data.get("email", user.email)
            user.save()
            if users_data.get("password", None):
                user.set_password(users_data.get("password"))
                user.save()
        except KeyError:
            instance.comment = validated_data.get('comment', instance.comment)
            instance.timezone = validated_data.get("timezone", instance.timezone)
            instance.expire_date = validated_data.get("expire_date", instance.expire_date)
            instance.save()
            user = instance.user
            user.save()
        return instance

    def validate(self, data):
        """validate data"""
        timezone_validation(data)
        password_validation(data)
        validate_expire_date(data)
        if 'user' not in data:
            raise ValidationError({'status': 'error', 'detail': "Invalid request format"})
        if 'password' in data['user']:
            if check_password(data['user']['password'], self.instance.user.password):
                raise ValidationError({'status': 'error', 'detail': 'The password must be different from '
                                                                    'the previous one'})
            if (self.instance.user == self.context['request'].user and
                    not check_password(data['user'].get('old_password', ''), self.instance.user.password)):
                raise ValidationError({'status': 'error', 'detail': 'Provide correct old password'})
        if 'is_active' in data['user']:
            if self.context['request'].user == self.instance.user and not data['user']['is_active']:
                raise ValidationError({'status': 'error', 'detail': "You can't disable your account"})
        return data

    class Meta:
        model = UserInfo
        fields = "__all__"
