import importlib


class Register(object):
    def __init__(self, registry_name):
        self._dict = {}
        self._name = registry_name

    def __setitem__(self, key, value):
        if not callable(value):
            raise Exception(f"Value of a Registry must be a callable!\nValue: {value}")
        if key is None:
            key = value.__name__
        if key in self._dict:
            print("Key %s already in registry %s." % (key, self._name))
        self._dict[key] = value

    def register(self, target):
        """Decorator to register a function or class."""

        def add(key, value):
            self[key] = value
            return value

        if callable(target):
            # @reg.register
            return add(None, target)
        # @reg.register('alias')
        return lambda x: add(target, x)

    def __getitem__(self, key):
        return self._dict[key]

    def __contains__(self, key):
        return key in self._dict

    def keys(self):
        """key"""
        return self._dict.keys()


class Registers(object):
    def __init__(self):
        raise RuntimeError("Registries is not intended to be instantiated")
    model = Register('model')


MODEL_MODULES = ["seq2seq", "hred"]
ALL_MODULES = [("deepdialog.model", MODEL_MODULES)]


def _handle_errors(errors):
    """Log out and possibly reraise errors during import."""
    if not errors:
        return
    for name, err in errors:
        print("Module {} import failed: {}".format(name, err))


def import_all_modules_for_register(custom_module_paths=None):
    """Import all modules for register."""
    modules = []
    print(ALL_MODULES)
    for base_dir, mod in ALL_MODULES:
        for name in mod:
            full_name = base_dir + "." + name
            modules.append(full_name)
    print(custom_module_paths)
    if isinstance(custom_module_paths, list):
        modules += custom_module_paths
    errors = []
    print(modules)
    for module in modules:
        try:
            importlib.import_module(module)
            print("successful load %s." % module)
        except ImportError as error:
            errors.append((module, error))
    _handle_errors(errors)
