"""
https://docs.python.org/3.9/howto/descriptor.html#complete-practical-example

In : type(c1).__dict__
Out:
mappingproxy({'__module__': '__main__',
              'name': <__main__.ConfigParameter at 0x7efe927a12e0>,
              'mode': <__main__.ConfigParameter at 0x7efe927a1940>,
              'url': <__main__.ConfigParameter at 0x7efe927a1be0>,
              'delay': <__main__.ConfigParameter at 0x7efe927a1190>,
              'format': <__main__.ConfigParameter at 0x7efeaae23a60>,
              'maxitems': <__main__.ConfigParameter at 0x7efeaad81400>,
              '__init__': <function __main__.Config.__init__(self)>,
              '__dict__': <attribute '__dict__' of 'Config' objects>,
              '__weakref__': <attribute '__weakref__' of 'Config' objects>,
              '__doc__': None})

In : type(c1).__dict__['format']
Out: <__main__.ConfigParameter at 0x7efeaae23a60>

In : type(c1).__dict__['format'].__dict__
Out:
{'envvar': 'HTTP_FETCHER_FORMAT',
 'description': 'File format',
 'default': 'json',
 'public_name': 'format',
 'private_name': '_format'}

Avec export HTTP_FETCHER_MODE="POST"

In : c1.__dict__
Out:
{'_name': None,
 '_mode': 'POST',
 '_url': None,
 '_delay': 3600,
 '_format': 'xml',
 '_maxitems': -1}
"""

import logging
import os

logging.basicConfig(level=logging.DEBUG)


class ConfigParameter:
    def __init__(self, envvar=None, description=None, default=None):
        """
        Should we define positionnal parameters or use defaut values as
        None or one other.
        """
        self.envvar = envvar
        self.description = description
        self.default = default

    def __set_name__(self, owner, name):
        """Called at the time the owning class "owner" is created.
        The descriptor has been assigned to "name".
        https://docs.python.org/3/howto/descriptor.html#automatic-name-notification

        https://docs.python.org/3/reference/datamodel.html#object.__set_name__
        """
        self.public_name = name
        self.private_name = f"_{name}"

    def __get__(self, obj, objtype=None):
        """"""
        value = getattr(obj, self.private_name)
        logging.info("Accessing %r giving %r", self.public_name, value)
        return value

    def __set__(self, obj, value):
        logging.info("Updating %r to %r", self.public_name, value)
        setattr(obj, self.private_name, value)

    def set_initial_value(self, obj):
        logging.info("Set initial value for %r", self.public_name)
        self.__set__(obj, os.environ.get(self.envvar, self.default))


class Config:

    name = ConfigParameter(
        envvar="HTTP_FETCHER_NAME", description="Name of the acquisition", default=None
    )
    mode = ConfigParameter(
        envvar="HTTP_FETCHER_MODE", description="http method", default="GET"
    )
    url = ConfigParameter(
        envvar="HTTP_FETCHER_URL", description="URL to fetch", default=None
    )
    delay = ConfigParameter(
        envvar="HTTP_FETCHER_DELAY",
        description="Delay between requests in seconds",
        default=3600,
    )
    # format is not a Python keyword,
    # https://docs.python.org/3.8/reference/lexical_analysis.html#keywords
    format = ConfigParameter(
        envvar="HTTP_FETCHER_FORMAT", description="File format", default="json"
    )
    maxitems = ConfigParameter(
        envvar="HTTP_FETCHER_MAXITEMS", description="Max number of fetches", default=-1
    )

    def __init__(self):
        for p in vars(type(self)):
            if isinstance(type(self).__dict__[p], ConfigParameter):
                type(self).__dict__[p].set_initial_value(self)


if __name__ == "__main__":
    logging.debug(f"vars(Config) = {vars(Config)}")
    logging.debug(f"vars(vars(Config)['mode']) = {vars(vars(Config)['mode'])}")

    c1 = Config()

    logging.debug(vars(c1))
    logging.debug(f"vars(Config)['mode'].__dict__ = {vars(Config)['mode'].__dict__}")

    c1.format = "xml"

    c2 = Config()

    c2.format = "csv"

    logging.debug(f"c1.format = {c1.format}, c2.format = {c2.format}")