"""
https://docs.python.org/3.8/reference/datamodel.html#slots

__slots__ are implemented at the class level by creating descriptors (Implementing Descriptors) for each variable name.
"""

import collections
from http import HTTPStatus
import os
from urllib import request
from urllib.error import URLError


# For validation
ACCEPTED_FORMATS = ('json', 'csv', 'xml')

class Config:

    __slots__ = ('name', 'mode', 'url', 'delay', 'format', 'maxitems')

    def __init__(self, defaults):
        # Initialisation
        self.name = os.environ.get(defaults['name'].envvar, defaults['name'].default)
        self.mode = os.environ.get(defaults['mode'].envvar, defaults['mode'].default)
        self.url = os.environ.get(defaults['url'].envvar, defaults['url'].default)
        self.delay = os.environ.get(defaults['delay'].envvar, defaults['delay'].default)
        self.format = os.environ.get(defaults['format'].envvar, defaults['format'].default)
        self.maxitems = os.environ.get(defaults['maxitems'].envvar, defaults['maxitems'].default)

    def valid_format(self):
        # Do we accept None value ?
        if self.format not in ACCEPTED_FORMATS:
            raise ValueError(f"Expected {self.format!r} to be one of {ACCEPTED_FORMATS!r}")

    def valid_url(self):
        # Do we accept None value ?
        try:
            response = request.urlopen(self.url)
        except URLError as e:
            # Avoid showing all stacktrace with URLError and OSError
            # https://docs.python.org/3.9/tutorial/errors.html#exception-chaining
            raise ValueError(f'Expected {self.url} should is triggering an error {e}') from None
        else:
            # What about moved content 301 (MOVED_PERMANENTLY) or 
            # cached content 304 (NOT_MODIFIED)
            if response.status != HTTPStatus.OK:
                raise ValueError(f'Expected {self.url} should be a valid URL {response.status}')


if __name__ == "__main__":
    # Using namedtuple to better manipulated defaults
    # https://docs.python.org/3.8/library/collections.html#collections.namedtuple
    # ---------------------------------------------------------------------------
    fparam = collections.namedtuple('FetcherParameters', ['name', 'envvar', 'description', 'default'])

    fetcher_defaults = {
            'name': fparam(name='name', envvar='HTTP_FETCHER_NAME', description='Name of the acquisition', default=None),
            'mode': fparam(name='mode', envvar='HTTP_FETCHER_MODE', description='http method', default='GET'),
            'url': fparam(name='url', envvar='HTTP_FETCHER_URL', description='URL to fetch', default=None),
            'delay': fparam(name='delay', envvar='HTTP_FETCHER_DELAY', description='Delay between requests in seconds', default=3600),
            'format': fparam(name='format', envvar='HTTP_FETCHER_FORMAT', description='File format', default='json'),
            'maxitems': fparam(name='maxitems', envvar='HTTP_FETCHER_MAXITEMS', description='Max number of fetches', default=-1)
            }

    print(f"-- vars(Config) = {vars(Config)}")

    c = Config(fetcher_defaults)

    print("-- After instanciation")
    for k in fetcher_defaults.keys():
        print(f"c.{k} = {getattr(c, k)}, ")

    c.format = 'xml'
    c.valid_format()

    print("-- After format change")
    for k in fetcher_defaults.keys():
        print(f"c.{k} = {getattr(c, k)}, ")

    c.url = 'https://www.twitterfountain.com/'
    #c.url = 'https://download.data.grandlyon.com/ws/ldata/velov.stations/all.json?maxfeatures=5&start=1'
    c.valid_url()