import json
from typing import OrderedDict


def build_list_of_dicts(val):
    """
    Converts a value that can be presented as a list of dict.

    In case top level item is not a list, it is wrapped with a list

    Valid values examples:
        - Valid dict: {"k": "v", "k2","v2"}
        - List of dict: [{"k": "v"}, {"k2","v2"}]
        - JSON decodable string: '{"k": "v"}', or '[{"k": "v"}]'
        - List of JSON decodable strings: ['{"k": "v"}', '{"k2","v2"}']

    Invalid values examples:
        - ["not", "a", "dict"]
        - [123, None],
        - [["another", "list"]]

    :param val: Input value
    :type val: Union[list, dict, str]

    :return: Converted(or original) list of dict
    :raises: ValueError in case value cannot be converted to a list of dict
    """
    if val is None:
        return []

    if isinstance(val, str):
        # use OrderedDict to preserve order
        val = json.loads(val, object_pairs_hook=OrderedDict)

    if isinstance(val, dict):
        val = [val]

    for index, item in enumerate(val):
        if isinstance(item, str):
            # use OrderedDict to preserve order
            val[index] = json.loads(item, object_pairs_hook=OrderedDict)
        if not isinstance(val[index], dict):
            raise ValueError("Expected a list of dicts")
    return val