def search_engine(encoded_query, inverted_idx):
    """takes an encoded query and the inverted_idx, searches in the inverted_idx and
       returns a list of the documents that contain all the tokens in the query

    Args:
        encoded_query (list): a textual query, encoded in integer
        inverted_idx (dict): a mapping between encoded words (integers) and the documents that contain the word

    Returns:
        [list]: a list of the documents that contain all the tokens in the query
    """
    result = []

    if not encoded_query:
        return result
    else:  
        # selects only the list corresponding to the words that appear in the query
        selected_lists = [inverted_idx[token] for token in encoded_query]

        idx = [0] * len(selected_lists) # start at index 0 for each list
        lists_len = [len(my_list) for my_list in selected_lists]
        selected_lists2 = list(enumerate(selected_lists))

        # checks if any list index surpasses the last element
        while all([k < m for k, m in zip(idx, lists_len)]):
            max_num = max([docs[idx[list_num]] for list_num, docs in selected_lists2]) # get the max document number
            
            # handles the case when each list is pointing at the same value
            if all([docs[idx[list_num]] == max_num for list_num, docs in selected_lists2]):
                result.append(max_num)
                idx = [i+1 for i in idx]
            
            # handles all the other cases, increasing idx on all lists that are not pointing at the max value
            else:
                j = 0
                for my_list in selected_lists:
                    if my_list[idx[j]] == max_num:
                        pass
                    else:
                        idx[j] += 1
                    j += 1
        
        return result