import mimetypes
import os
from typing import Dict, Optional


def merge_dicts(dict_a: Dict, dict_b: Dict) -> Dict:
    """Merge two dictionaries (shallow).

    Arguments:
        dict_a (dict): The dictionary to use as the base.
        dict_b (dict): The dictionary to update the values with.

    Returns:
        dict: A new merged dictionary.

    """
    dict_z = dict_a.copy()
    dict_z.update(dict_b)
    return dict_z


def deep_merge_dicts(dict_a: Dict, dict_b: Dict, _path=None) -> Dict:
    """Merge two dictionaries (deep).
    https://stackoverflow.com/questions/7204805/how-to-merge-dictionaries-of-dictionaries/7205107#7205107

    Arguments:
        dict_a (dict): The dictionary to use as the base.
        dict_b (dict): The dictionary to update the values with.
        _path (list): internal use.

    Returns:
        dict: A new merged dictionary.

    """
    if _path is None:
        _path = []
    for key in dict_b:
        if key in dict_a:
            if isinstance(dict_a[key], dict) and isinstance(dict_b[key], dict):
                deep_merge_dicts(dict_a[key], dict_b[key], _path + [str(key)])
            elif dict_a[key] == dict_b[key]:
                pass # same leaf value
            else:
                raise Exception('Conflict at %s' % '.'.join(_path + [str(key)]))
        else:
            dict_a[key] = dict_b[key]
    return dict_a


def guess_mime(path: str) -> Optional[str]:
    """Guess the mime type for a given path.

    Arguments:
        root (str): the root path of the file tree
        path (str): the sub-path within the file tree

    Returns:
        str: the guessed mime-type

    """
    mtypes = mimetypes.guess_type(path)
    ftype = None
    if os.path.isdir(path):
        ftype = "directory"
    elif os.access(path, os.F_OK) and mtypes[0]:
        ftype = mtypes[0]
    else:
        ftype = "application/octet-stream"
    return ftype
