from typing import Union
from pathlib import Path
import hashlib
from typing import Callable


def checksum(path: Union[str, Path], hash_fn: str = "sha256", chunk_num_blocks=8192, **kwargs) -> str:
    """Return checksum of file or directory.

    Args:
        path (Union[str, Path]): A path to file or directory.
        hash_fn (str): A hash function to use. Defaults to 'sha256'.
        chunk_num_blocks (int): A number of blocks to read at once. Defaults to 8192.
        **kwargs: Additional arguments to pass to hash function.

    Returns:
        str: checksum of file or directory
    """

    if hasattr(hashlib, hash_fn):
        hash_func: Callable = getattr(hashlib, hash_fn)
    else:
        raise ValueError("Unknown hash function")

    hashlib.blake2b
    h: hashlib._Hash = hash_func(**kwargs)
    path = Path(path)

    if path.is_file():
        path_list = [path]
    else:
        path_list = sorted(path.glob("**/*"))

    for path in path_list:
        if not path.is_file():
            continue

        with path.open("rb") as f:
            for chunk in iter(lambda: f.read(chunk_num_blocks * h.block_size), b""):
                h.update(chunk)
    return h.hexdigest()