# Dynamic import
import importlib

# Get function args
import inspect

# check file properties
import os

# The directory where student work will be
# not a real path, do not use ./ or stuff like this
BASE_MODULE_PATH = 'python_app/modules'
if BASE_MODULE_PATH != '':
    BASE_MODULE_PATH += '/'


def application(env, start_response):
    """ Cette fonction est appellée à chaque requête HTTP et doit exécuter le bon code python. """

    path = env['PATH_INFO'][1:] # removing first slash
    # slash stuff
    if path.endswith('/'):
        path = path[:-1]
    path_elements = tuple(d for d in path.split('/') if d != '')
    path_minus_one = '/'.join(path_elements[:-1])

    # Find which python module and function will be called
    if os.path.isfile(BASE_MODULE_PATH + path_minus_one):
        path = path_minus_one
        function = path_elements[-1]
    elif os.path.isfile(BASE_MODULE_PATH + path):
        path = path_minus_one + '/main'
        function = 'index'
    elif os.path.isdir(BASE_MODULE_PATH + path):
        path += '/main'
        function = 'index'
    else:
        return htmlresp(404, 'Le fichier ou dossier <em>{}</em> n’a pas été trouvé.'.format(path), start_response)

    # Module full path
    module_path = BASE_MODULE_PATH + path
    module_path = module_path.replace('/', '.')

    # Import the function
    try:
        m = importlib.import_module(module_path)
        importlib.reload(m)
    except ModuleNotFoundError:
        print('Le fichier {} n’a pas été trouvé. {}'.format(module_path, str(path_elements)))
        return htmlresp(404, 'Le fichier <em>{}</em> n’a pas été trouvé.'.format(path), start_response)

    # Find which parameters the function needs
    try:
        f = getattr(m,function)
        # Call the function with the rigth attributes
    except AttributeError:
        return htmlresp(404, 'La fonction <em>{}</em> n’a pas été trouvée dans {}'.format(function, module_path), start_response)

    # Pass url parameters to the function
    try:
        #print(inspect.getargspec(f))
        #params = {p:(d if d is not None else '') for p,d in zip(inspect.getargspec(f).args, inspect.getargspec(f).defaults)}
        expected_params = inspect.getargspec(f).args
        params = {}
        # TODO POST params?
        for item in env['QUERY_STRING'].split('&'):
            if item == '':
                continue
            k,v = tuple(item.split('='))
            if k in expected_params:
                params[k] = v
    except Exception:
        return htmlresp(400, 'La fonction <em>{}</em> demande les arguments suivants : {}. On a uniquement {}.'.format(function, params, ), start_response)

    try:
        response = f(**params)
        if type(response) is tuple:
            return htmlresp(response[0], str(response[1]), start_response, False)
        else:
            return htmlresp(200, str(response), start_response, False)
    except Exception as e:
        return htmlresp(400, 'Erreur à l’exécution de la fonction <em>{}</em>.<pre style="color:#d90303;">{}</pre>'.format(function, e), start_response)


def htmlresp(code, message, start_response, squelette=True):
    """ Cette fonction crée le squelette HTML minimal """
    html = '<!DOCTYPE html><html><head><meta charset="utf-8"/></head><body>{}</body></html>'
    return resp(code, [('Content-Type','text/html')], html.format(message) if squelette else message, start_response)

def resp(code, headers, message, start_response):
    """ Cette fonction permet de faire une réponse HTTP """
    start_response(str(code), headers)
    return bytes(message, 'utf8')
