##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2026, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
#########################################################################

"""This file contains functions for creating dynamic registry meta class."""

from abc import ABCMeta


# Constructor
def __constructor(self, name, bases, kwargs):
    # Register this type of auth_sources, based on the module name
    # Avoid registering the BaseAuthentication itself
    cls = self.__class__
    entry = self._decorate_cls_name(name, kwargs)

    if cls._registry is None:
        cls._registry = dict()
    else:
        if entry in cls._registry:
            raise RuntimeError((
                "{} class is already been registered with {} "
                "(package: {})"
            ).format(entry, cls._name_, cls._package_))

    if cls._initialized is True:
        cls._registry[entry] = self
    cls._initialized = True

    ABCMeta.__init__(self, name, bases, kwargs)


@classmethod
def __get(cls, name, **kwargs):
    if name in cls._objects:
        return cls._objects[name]

    if cls._registry is not None and name in cls._registry:
        cls._objects[name] = (cls._registry[name])(**kwargs)

        return cls._objects[name]

    raise NotImplementedError(
        "{} '{}' has not been implemented.".format(cls.__name__, name)
    )


@classmethod
def __load_modules(cls, app=None):
    # Initialize the registry only if it has not yet been initialized
    if cls._registry is None:
        cls._registry = dict()

    from importlib import import_module
    from werkzeug.utils import find_modules

    for module_name in find_modules(cls._package_, True):
        module = import_module(module_name)

        if "init_app" in module.__dict__.keys():
            module.__dict__["init_app"](app)


def __get_module_name(self, name, kwargs):
    module_name = kwargs["__module__"]
    length = len(self._package_) + 1

    if len(module_name) > length and module_name.startswith(self._package_):
        return module_name[length:]

    return module_name


def __get_class_name(self, name, kwargs):
    return name


def create_registry_metaclass(name, package, load_modules=__load_modules,
                              decorate_as_module=True):

    class_params = {
        # constructor
        "__init__": __constructor,

        # Class members
        "_registry": None,
        "_objects": dict(),
        "_package_": package,

        # Member functions
        "get": __get,
        "load_modules": load_modules,
        "_name_": name,
        "_decorate_cls_name": __get_module_name
        if decorate_as_module is True else __get_class_name,
        "_initialized": False,
    }

    # Creating class dynamically
    return type(package + "." + name, (ABCMeta, ), class_params)
