from mongoengine.queryset.visitor import Q

from app.models import User
 
class AuthService:
    @staticmethod
    def create_user(data):
        """ 
        Create a new user.
        :param data: A dictionary containing user data.
        :return: The created user document.
        """
        user = User(**data)
        user.set_password(data['password'])
        user.save()
        return user
    
    @staticmethod
    def get_user_by_id(user_id):
        """
        Get a user by their ID.
        :param user_id: The ID of the user.
        :return: The user document or None if not found.
        """
        user = User.objects(public_id=user_id).first()
        return user
    
    @staticmethod
    def get_user_by_email_or_username(email_or_username):
        """
        Get a user by their email or username.
        :param email_or_username: The email or username of the user.
        :return: The user document or None if not found.
        """
        user = User.objects(Q(email=email_or_username) | Q(username=email_or_username)).first()
        return user
    
    @staticmethod
    def get_user_by_email(email):
        """
        Get a user by their email.
        :param email: The email of the user.
        :return: The user document or None if not found.
        """
        user = User.objects(email=email).first()
        return user
    
    @staticmethod
    def search_users_by_keyword(keyword):
        """
        Search for users containing a keyword in their name, email, or other attributes.
        :param keyword: The keyword to search for.
        :return: A list of matching user documents.
        """
        users = User.objects(Q(username__icontains=keyword) | Q(email__icontains=keyword))
        return users
    
    @staticmethod
    def authenticate(email_or_username, password):
        """
        Authenticate a user using their email and password.
        :param email: The email of the user.
        :param password: The password provided by the user.
        :return: The authenticated user document if successful, None if authentication fails.
        """
        user = AuthService.get_user_by_email(email_or_username)
        if user and user.check_password(password):
            return user
        return None
    
    @staticmethod
    def change_password(user_id, new_password):
        """
        Change the password of a user.
        :param user_id: The ID of the user to update the password for.
        :param new_password: The new password.
        :return: True if the password is updated, False if the user is not found.
        """
        user = AuthService.get_user_by_id(user_id)
        if user:
            user.set_password(new_password)
            user.save()
            return True
        else:
            return False
        
    @staticmethod
    def promote_user(user_id, new_role):
        """
        Promote a user by changing their role.
        :param user_id: The ID of the user to promote.
        :param new_role: The new role for the user.
        :return: The updated user document with the new role, or None if not found.
        """
        user = AuthService.get_user_by_id(user_id)
        if user:
            user.role = new_role
            user.save()
            return user.to_dict()
        else:
            return None  # or raise an exception
        
    @staticmethod
    def reset_password(user_id, new_password):
        """
        Reset the password of a user.
        :param user_id: The ID of the user to reset the password for.
        :param new_password: The new password.
        :return: True if the password is reset, False if the user is not found.
        """
        user = AuthService.get_user_by_id(user_id)
        if user:
            user.set_password(new_password)
            user.save()
            return True
        else:
            return False
        
    
