import typing as t


def construct_filtered_dict(
    func: t.Callable[[t.Any], bool] = bool,
    /,
    **kwargs: t.Any,
) -> dict[str, t.Any]:
    return {k: v for k, v in kwargs.items() if func(v)}


def wipe(
    data: dict,
    *,
    keys: list[t.Hashable] | tuple[t.Hashable, ...] | t.Hashable,
    copy: bool = False,
) -> dict:
    if copy:
        data = data.copy()

    if not isinstance(keys, (tuple, list)):
        keys = (keys,)
    for k in keys:
        data.pop(k, None)

    return data


def rekey(
    data: dict,
    *,
    key: t.Hashable,
    new_key: t.Hashable,
    copy: bool = False,
) -> dict:
    if copy:
        data = data.copy()

    value = data.pop(key)
    data[new_key] = value

    return data


def new(data: dict, *exclude, **updates) -> dict:
    new_data = data.copy()
    for ex in exclude:
        new_data.pop(ex, None)
    new_data.update(updates)
    return new_data


def mutate_values(
    data: dict,
    *,
    keys: t.Sequence[t.Hashable],
    func: t.Callable[[t.Any], t.Any],
    copy: bool = False,
) -> dict:
    if copy:
        data = data.copy()
    for k in keys:
        data[k] = func(data[k])
    return data
