Issues animating the rubik's cube

I have a script that generates a random rubik’s cube, solves it (using a library) and makes an animation of said solution. But I have issues with the animation stage.

The cube is represented as a collection of smaller cubes.

The animation finishes with correct result but the rotations are not animated properly.

*_objects() functions are responsible for selecting cubes corresponding to faces.

#set origin to cursor
for obj in collection.objects:
    obj.select_set(True)
    obj.rotation_mode = "QUATERNION"
bpy.ops.object.origin_set(type='ORIGIN_CURSOR')

#animate
def rotation_animate(select_axis,angle):
    #bpy.data.scenes['Scene'].frame_set(frame)
    for ob in bpy.context.selected_objects:
        #center = get_cube_center(ob)
        #if isclose(center[select_axis], position, abs_tol=0.1):
        q_axis = [0.0, 0.0, 0.0]
        q_axis[select_axis] = 1.0

        q_delta = Quaternion(q_axis, angle)
        q = q_delta @ ob.rotation_quaternion
        ob.rotation_quaternion = q


def rotate_animation(collection, rotation):
    #'F', 'R', 'U', 'B', 'L', 'D', "F'", "R'", "B'", "L'", "D'"
    axis = "X"
    angle = 90
    bpy.ops.object.select_all(action='DESELECT')
    if rotation == "F":
        front_objects = get_front(collection)
        select_all(front_objects)
        axis ="y"
        angle = -90
        #return front_objects
    elif rotation == "R":
        right_objects = get_right(collection)
        select_all(right_objects)
        axis = "x"
        angle = 90
        #return right_objects
    elif rotation == "U":
        top_objects = get_top(collection)
        select_all(top_objects)
        axis = "z"
        angle = 90
        #return top_objects
    elif rotation == "B":
        back_objects = get_back(collection)
        select_all(back_objects)
        axis = "y"
        angle = 90
        #return back_objects
    elif rotation == "L":
        left_objects = get_left(collection)
        select_all(left_objects)
        axis = "x"
        angle = -90
        #return left_objects
    elif rotation == "D":
        bottom_objects = get_bottom(collection)
        select_all(bottom_objects)
        axis = "z"
        angle = -90
        #return bottom_objects
    elif rotation == "F'":
        front_objects = get_front(collection)
        select_all(front_objects)
        axis = "y"
        angle = 90
        #return front_objects
    elif rotation == "R'":
        right_objects = get_right(collection)
        select_all(right_objects)
        axis = "x"
        angle = -90
        #return right_objects
    elif rotation == "B'":
        back_objects = get_back(collection)
        select_all(back_objects)
        axis = "y"
        angle = -90
        #return back_objects
    elif rotation == "L'":
        left_objects = get_left(collection)
        select_all(left_objects)
        axis = "x"
        angle = 90
        #return left_objects
    elif rotation == "D'":
        bottom_objects = get_bottom(collection)
        select_all(bottom_objects)
        axis = "z"
        angle = 90
        #return bottom_objects
    elif rotation == "U'":
        top_objects = get_top(collection)
        select_all(top_objects)
        axis = "z"
        angle = -90
        #return top_objects
    axis_dict = {"y":1, "x":0, "z":2}
    axis = axis_dict[axis]
    rotation_animate(axis, angle)
    selected_objects = [obj for obj in bpy.context.selected_objects]
    return selected_objects
    #bpy.ops.object.transform_apply(rotation=True, scale=False, location=False)


frame_start = 1
frame_duration = 10  # Number of frames for each move
current_frame = 1
idx = 0
for move in solution_moves:
    selected = []
    if "2" in move:
        for i in range(0, 2):
            idx += 1
            current_frame = frame_start + idx * frame_duration
            short_move = move.replace("2", "")
            selected = rotate(collection, short_move)
            for obj in selected:
                obj.keyframe_insert(data_path="rotation_quaternion", frame=current_frame)
                #obj.keyframe_insert(data_path="location", frame=current_frame)
    else:
        idx += 1
        current_frame = frame_start + idx * frame_duration
        selected = rotate(collection, move)
        for obj in selected:
            obj.keyframe_insert(data_path="rotation_quaternion", frame=current_frame)
            #obj.keyframe_insert(data_path="location", frame=current_frame)



bpy.context.scene.frame_end = current_frame + 30