from typing import List, Union, Any, Dict, get_origin, Optional


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 get_dict_path_value(
    dict_value: dict,
    path: Union[str, List[str]],
    default_value: Any = None
) -> Any:
    used_path = path
    if not isinstance(used_path, list):
        used_path = [used_path]
    result = default_value
    current_value = dict_value

    for field in used_path:
        if current_value is not None and field in current_value:
            current_value = current_value[field]
            result = current_value
        else:
            result = default_value
            break

    if result is None:
        return default_value
    return result


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 _get_alias_origin(type_param, _default=None) -> Optional[Any]:
    return getattr(type_param, "__origin__", _default)


def is_optional(type_param):
    return (
        _get_alias_origin(type_param) == Union and
        len(getattr(type_param, "__args__") or []) == 2 and
        (
            get_origin(type_param.__args__[0]) is None
            or get_origin(type_param.__args__[1]) is None
        )
    )


def is_typing_alias(type_param):
    return _get_alias_origin(type_param) is not None


def is_list(type_param):
    return _get_alias_origin(type_param) in [list, List]


def is_dict(type_param):
    return _get_alias_origin(type_param) in [dict, Dict]


def is_union(type_param):
    return _get_alias_origin(type_param) in [Union]


def is_type(cls):
    return isinstance(_get_alias_origin(cls, cls), type)


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


def get_inner_optional_type(type_param):
    type_params = get_type_params(type_param)
    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


def to_camel_case(text):
    text = text.replace("-", "_")
    words = text.split("_")
    return words[0].lower() + ''.join(word.capitalize() for word in words[1:])
