from typing import List, Union, Any, Dict


def set_dict_path_value(dict_value: dict, path: Union[str, List[str]], value: Any):
    used_path = path
    if not isinstance(used_path, list):
        used_path = [used_path]

    pivot = dict_value
    last_index = len(used_path) - 1
    for i, p in enumerate(used_path):
        if i == last_index:
            pivot[p] = value
        else:
            if pivot.get(p) is None:
                pivot[p] = {}
            pivot = pivot[p]


def build_ref(path: Union[str, List[str]], name: str) -> str:
    used_path = path
    if not isinstance(used_path, list):
        used_path = [used_path]
    return '/'.join([
        '#',
        *used_path,
        name
    ])


def is_optional(new_type):
    return (
        getattr(new_type, "__origin__", None) == Union and
        len(getattr(new_type, "__args__") or []) == 2 and
        (isinstance(None, new_type.__args__[1]) or isinstance(None, new_type.__args__[0]))
    )


def is_list(new_type):
    return getattr(new_type, '__origin__', new_type) in [list, List]


def is_dict(new_type):
    return getattr(new_type, '__origin__', new_type) in [dict, Dict]


def is_type(cls):
    return isinstance(getattr(cls, '__origin__', cls), type)


def get_type_params(new_type):
    return getattr(new_type, "__args__", []) or []


def get_inner_optional_type(new_type):
    type_params = get_type_params(new_type)
    if len(type_params) > 0:
        if len(type_params) == 1 or isinstance(None, type_params[1]):
            return type_params[0]
        else:
            return type_params[1]
    return None
