from django.db.models import Q
from rest_framework import serializers

from apps.account import models
from base.serializers import DynamicFieldsSerializer, DynamicFieldsModelSerializer


class UserLoginOrRegistrationSerializer(DynamicFieldsSerializer):
    """
    This is the UserLoginOrRegistrationSerializer.

    It is used for serializing user data during login or registration.

    Fields:
        mobile_number (str): The mobile number of the user.
        mobile_country_code (str): The mobile country code associated with the user.
        email (str): The email address of the user.
    """

    mobile_number = serializers.CharField(required=False, allow_blank=False, allow_null=False)
    mobile_country_code = serializers.CharField(required=False, allow_blank=False, allow_null=False)
    email = serializers.EmailField(required=False, allow_blank=False, allow_null=False)

    def validate(self, attrs):
        email = attrs.get("email")
        mobile_number = attrs.get("mobile_number")
        mobile_country_code = attrs.get("mobile_country_code")

        if not email and not (mobile_number and mobile_country_code):
            raise serializers.ValidationError({"field_required":"Either email or mobile number with country code must be provided."})

        if email and (mobile_number or mobile_country_code):
            raise serializers.ValidationError({"field_conflict":"Provide either email or mobile number with country code, not both."})

        if not email:
            if not mobile_number.isdigit():
                raise serializers.ValidationError({"mobile_number":"Mobile number must contain only digits."})

            if not len(mobile_number)==10:
                raise serializers.ValidationError({"mobile_number":"Mobile number must be 10 digits long."})

            if not mobile_country_code.lstrip("+").isdigit():
                raise serializers.ValidationError({"mobile_country_code":"Mobile country code must contain only digits."})
        return attrs

class VerifyOtpSerializer(DynamicFieldsSerializer):
    """
    This serializer is used for validating and deserializing OTP verification data.

    Fields:
        email (str): The user's email.
        otp (str): The one-time password for verification.

    These fields are required and should not be blank or null.

    Inherits from DynamicFieldsSerializer to provide flexibility in specifying fields.
    """

    mobile_number = serializers.CharField(required=False, allow_blank=False, allow_null=False)
    mobile_country_code = serializers.CharField(required=False, allow_blank=False, allow_null=False)
    email = serializers.EmailField(required=False, allow_blank=False, allow_null=False)
    otp = serializers.CharField(required=True, allow_blank=False, allow_null=False)

    def validate(self, attrs):
        email = attrs.get("email")
        mobile_number = attrs.get("mobile_number")
        mobile_country_code = attrs.get("mobile_country_code")

        if not email and not (mobile_number and mobile_country_code):
            raise serializers.ValidationError({"field_required":"Either email or mobile number with country code must be provided."})

        if email and (mobile_number or mobile_country_code):
            raise serializers.ValidationError({"field_conflict":"Provide either email or mobile number with country code, not both."})

        if not email:
            if not mobile_number.isdigit():
                raise serializers.ValidationError({"mobile_number":"Mobile number must contain only digits."})

            if not len(mobile_number)==10:
                raise serializers.ValidationError({"mobile_number":"Mobile number must be 10 digits long."})

            if not mobile_country_code.lstrip("+").isdigit():
                raise serializers.ValidationError({"mobile_country_code":"Mobile country code must contain only digits."})
        return attrs

class ProfileSerializer(DynamicFieldsModelSerializer):
    """
    This serializer is used for validating and deserializing OTP verification data and user profile updates.

    Fields:
        mobile_number (str): The user's mobile number.
        mobile_country_code (str): The country code of the user's mobile number.
        otp (str): The one-time password for verification.

    These fields are required and should not be blank or null.

    Inherits from DynamicFieldsModelSerializer to provide flexibility in specifying fields.

    Meta:
        model (User): The model used for serialization and deserialization.
        fields (str): The fields to include in the serialization.
        read_only_fields (str): The fields that are read-only.

    Methods:
        update(instance, validated_data): Updates the user profile, validating and saving changes.
    """

    class Meta:
        model = models.User
        fields = (
            "id",
            "name",
            "email",
            "profile_pic",
            "mobile_number",
            "mobile_country_code",
        )
        read_only_fields = ["id"]

    def update(self, instance, validated_data):
        """
        Update the user profile, validating and saving changes.

        Args:
            instance (User): The user profile instance to update.
            validated_data (dict): Validated data containing user profile details.

        Returns:
            User: The updated user profile.

        This method handles the update of user profile data, validates changes, and saves the updated profile.
        It ensures that the user has permission to update their own profile and checks for email uniqueness.
        """
        request = self.context.get("request")

        if instance != request.user and not request.user.is_superuser:
            raise serializers.ValidationError(
                "You have no permission to update this user profile"
            )
        email = validated_data.get("email")
        mobile_number = validated_data.get("mobile_number")
        mobile_country_code = validated_data.get("mobile_country_code")

        if (
            email
            and models.User.objects.filter(
                Q(email=email) & ~Q(id=request.user.id)
            ).exists()
        ):
            raise serializers.ValidationError("This email is already in use.")

        if (
            mobile_number
            and mobile_country_code
            and models.User.objects.filter(
                Q(mobile_number=mobile_number)
                & Q(mobile_country_code=mobile_country_code)
                & ~Q(id=request.user.id)
            ).exists()
        ):
            raise serializers.ValidationError("This mobile number is already in use.")

        for attr, value in validated_data.items():
            if attr == "profile_pic":
                instance.profile_pic = value
            else:
                if attr == "email" and request.user.is_superuser:
                    pass
                else:
                    setattr(instance, attr, value)
        instance.save()
        return instance
