from flask import make_response, request, current_app, Flask, jsonify
from functools import update_wrapper
import json
import wrapper as wp
import ela_user_account as eua
import prj_common as pc
from six import string_types
from datetime import timedelta
import Ela_Spacy as ls
import user_message_mgt as um
import user_session as us
import logging
import partners as pa
import prj_common as mycommon
import ela_index_bdd_classes as ela_index_class
import class_mgt as cm
import Dev_api_functions as dev_function
from flask_cors import CORS, cross_origin
import time

DEBUG_LEVEL = logging.DEBUG
LOG_FILE_NAME = "./Log/log_file.log"


upload_folder = "./Data/"
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}


logging.basicConfig( level=DEBUG_LEVEL, filename=LOG_FILE_NAME)


app = Flask(__name__)
cors = CORS(app, resources={r"/foo": {"origins": "*"}})
app.config['CORS_HEADERS'] = 'Content-Type'
app.config['UPLOAD_FOLDER'] = upload_folder


def crossdomain(origin=None, methods=None, headers=None, max_age=21600,
                attach_to_all=True, automatic_options=True):
    """Decorator function that allows crossdomain requests.
      Courtesy of
      https://blog.skyred.fi/articles/better-crossdomain-snippet-for-flask.html
    """
    if methods is not None:
        methods = ', '.join(sorted(x.upper() for x in methods))
    # use str instead of basestring if using Python 3.x
    if headers is not None and not isinstance(headers, str):
        headers = ', '.join(x.upper() for x in headers)
    # use str instead of basestring if using Python 3.x
    if not isinstance(origin, str):
        origin = ', '.join(origin)
    if isinstance(max_age, timedelta):
        max_age = max_age.total_seconds()

    def get_methods():
        """ Determines which methods are allowed
        """
        if methods is not None:
            return methods

        options_resp = current_app.make_default_options_response()
        return options_resp.headers['allow']

    def decorator(f):
        """The decorator function
        """
        def wrapped_function(*args, **kwargs):
            """Caries out the actual cross domain code
            """
            if automatic_options and request.method == 'OPTIONS':
                resp = current_app.make_default_options_response()
            else:
                resp = make_response(f(*args, **kwargs))
            if not attach_to_all and request.method != 'OPTIONS':
                return resp

            h = resp.headers
            h['Access-Control-Allow-Origin'] = origin
            h['Access-Control-Allow-Methods'] = get_methods()
            h['Access-Control-Max-Age'] = str(max_age)
            h['Access-Control-Allow-Credentials'] = 'true'
            h['Access-Control-Allow-Headers'] = \
                "Origin, X-Requested-With, Content-Type, Accept, Authorization"
            if headers is not None:
                h['Access-Control-Allow-Headers'] = headers
            return resp

        f.provide_automatic_options = False
        return update_wrapper(wrapped_function, f)
    return decorator

@app.after_request
def after_request(response):
  response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
  response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')

  return response



'''
cette API gere le login et la creation du token
'''
@app.route('/myclass/api/login/', methods=['POST','GET'])
@crossdomain(origin='*')
def login():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = us.login(payload)
    return jsonify(status=status, message=retval)



'''
cette API recupere les objectifs d'un utilisateur

La clé est l'adresse email.
si le nom de la formation est fourni, alors l'api va retourner la formation donnée
'''
@app.route('/myclass/api/get_user_objectif/', methods=['POST','GET'])
@crossdomain(origin='*')
def get_user_objectif():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = eua.get_user_objectif(payload)
    return jsonify(status=status, message=retval)


'''
Cette API desactive un objectif.
les clés sont : 
- adresse email
- nom de l'objectif

'''
@app.route('/myclass/api/desable_user_objectif/', methods=['POST'])
@crossdomain(origin='*')
def desable_user_objectif():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = eua.desable_user_objectif(payload)
    return jsonify(status=status, message=retval)




'''
Cette API ajoute un objectif à un utilisateur
la clé est l'adresse email
'''
@app.route('/myclass/api/add_update_user_objectif/', methods=['POST'])
@crossdomain(origin='*')
def add_update_user_objectif():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = eua.add_update_user_objectif(payload)  
    return jsonify(status=status, message=retval)



'''
Cette Api retourne les info d'un user accout identifié par 
son adresse email.
'''
@app.route('/myclass/api/get_user_account/', methods=['POST','GET'])
@crossdomain(origin='*')
def get_user_account():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ", payload)
    result, message = eua.get_user_account(payload)
    return jsonify(status=result, message=message)


'''
Cette API créer un compte utilisateur et declenche l'envoi de l'email de notification
'''
@app.route('/myclass/api/add_user_account/', methods=['POST'])
@crossdomain(origin='*')
def add_user_account():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    mycommon.myprint(" add_user_account : info recues "+str(payload))
    result, message = eua.add_user_account(payload)
    return jsonify(status=result, message=message)


'''
Cette API valide une inscription d'un user
'''
@app.route('/myclass/api/valide_user_account/<value>', methods=['GET','POST'])
@crossdomain(origin='*')
def valide_user_account(value):

    print(" ### validation du compte = ",value)
    status, retval = eua.valide_user_account(value)
    return jsonify(status=status, message=retval)


'''
Cette api met à jour un compte utilisateur
'''
@app.route('/myclass/api/update_user_account/', methods=['POST','GET'])
@crossdomain(origin='*')
def update_user_account():
    payload = request.form.to_dict()
    print(" ### payload = ", payload)
    status, retval = eua.update_user_account(payload)
    return jsonify(status=status, message=retval)


@app.route('/myclass/api/create_class/', methods=['POST','GET'])
@crossdomain(origin='*')
def create_class():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = cm.add_class(payload)
    return jsonify(status=status, message=retval)



'''
Cette api recupete et affiche une formation.
la clé d'une formation est le code externe, 
mais pour que l'api fonctionne, il faut lui fournir

- le token du partenaire
'''
@app.route('/myclass/api/get_class/', methods=['POST','GET'])
@crossdomain(origin='*')
def get_class():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",str(payload)+"  IP requester = "+str(request.remote_addr))

    status, retval = cm.get_class(payload)
    return jsonify(status=status, message=retval)




@app.route('/myclass/api/update_class/', methods=['POST'])
@crossdomain(origin='*')
def update_class():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = cm.update_class(payload)
    return jsonify(status=status, message=retval)


'''
deverrouillage  d'une formation  - unlock training

'''
@app.route('/myclass/api/unlock_class/', methods=['POST'])
@crossdomain(origin='*')
def unlock_class():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = cm.unlock_class(payload)
    return jsonify(status=status, message=retval)

'''
Verrouillage  d'une formation  - lock training

'''
@app.route('/myclass/api/lock_class/', methods=['POST'])
@crossdomain(origin='*')
def lock_class():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = cm.lock_class(payload)
    return jsonify(status=status, message=retval)




'''
Desactivé une formation  - disable training

'''
@app.route('/myclass/api/disable_class/', methods=['POST'])
@crossdomain(origin='*')
def disable_class():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = cm.disable_class(payload)
    return jsonify(status=status, message=retval)

'''
Reactivation d'une formation  - enable training

'''
@app.route('/myclass/api/enable_class/', methods=['POST'])
@crossdomain(origin='*')
def enable_class():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = cm.enable_class(payload)
    return jsonify(status=status, message=retval)




'''
Cette api retourne les formations dont "attribut"="valeur"
'''
@app.route('/myclass/api/get_class_by_name/<attribut>,<value>', methods=['GET','POST'])
@crossdomain(origin='*')
def get_all_class_by_attribut(attribut, value):
    result = wp.get_all_class_by_attribut(attribut, value)
    if result:
        #print(" in main result =  ", result)
        return jsonify(result)

    return jsonify(status="False")


'''
Cette api retourne les formations dont "attribut" IN (list_valeurs)
list_valeurs = val1,val2,val3,...,valn
'''
@app.route('/myclass/api/get_class_by_list_attr/<attribut>;<list_values>', methods=['GET'])
@crossdomain(origin='*')
def get_class_by_list_attr(attribut, list_values):
    print(" ### attribut = "+attribut)

    result = wp.get_class_by_list_attr(attribut, list_values)
    if result:
        #print(" in main result =  ", result)
        return jsonify(result)
    return jsonify(status="False")


'''
fonction actuellement utilisé sur le front : 
Cette fonction "get_recherche_gle_class"  prend en argument une phrase et
retourne les formations associées
'''
@app.route('/myclass/api/get_recherche_gle_class/<sentence>', methods=['GET'])
@crossdomain(origin='*')
def get_recherche_gle_class(sentence):

    result = wp.get_recherche_gle_class(sentence)
    if result:
        #print(" in main result =  ", result)
        return jsonify(result)
    return jsonify(status="False")


'''
Fonction utilisée pour la recherche simple d'un texte.
sans utilisation de critère ni de tag

'''
@app.route('/myclass/api/recherche_text_simple/', methods=['GET','POST'])
@crossdomain(origin='*')
def recherche_text_simple():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ", payload)
    status, result = wp.recherche_text_simple(payload)
    return jsonify(status=status, message=result)



# recherche globale
'''
fonction NON utilisée sur le front : 
Cette fonction fait une recherche globale en prenant une chaine de caractère  - not use on front
'''
@app.route('/myclass/api/get_class_global_search/<search_string>', methods=['GET','POST'])
@crossdomain(origin='*')
def get_class_global_search(search_string):
    result = cm.get_class_global_search(search_string)
    if result:
        #print(" in main result =  ", result)
        return jsonify(result)

    return jsonify(status="False")


@app.route('/myclass/api/get_all_class/', methods=['GET','POST'])
@crossdomain(origin='*')
def get_all_class():
    status, result = wp.get_all_class()
    response =  jsonify(status=status, message=result)
    response.headers.add("Access-Control-Allow-Origin", "*")
    response.headers.add("Access-Control-Allow-Headers", "*")
    response.headers.add("Access-Control-Allow-Methods", "*")
    return response



@app.route('/myclass/api/update_class_by_attribut/<objId>,<attribut>,<value>', methods=['GET','POST'])
def update_class_by_attribut(objId, attribut, value):
    print(" update_class_by_attribut ")
    result = wp.update_class_by_attribut(objId, attribut, value)
    if result:
        print(" in main result =  ", result)
        return jsonify(result)

    return jsonify(status="False")

# this function update all fields of class.
# First : we retrieve all field of class and display it.
# Second : the user update some fields but all fields will be returned for update
# it means all field are stored in :
# payload = request.form.to_dict()
@app.route('/myclass/api/update_class_by_id/<id>', methods=['GET','POST'])
def update_class_by_id(id):
    payload = request.form.to_dict()
    print("on va modifier l'id (fourni en input) : ", id)
    for key, value in payload.items():
        print(key," : ", value)

    result = wp.update_class(payload)
    #result = "1"
    if result:
        return jsonify(status='True', message='Class updated')
    return jsonify(status='False')


'''
Cette API créer un compte patenaire / client  et declenche l'envoi de l'email de notification
La clé est reste l'adresse email du partenaire (pas du contact du partenaire)
'''
@app.route('/myclass/api/add_partner_account/', methods=['POST','GET'])
@crossdomain(origin='*')
def add_partner_account():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = pa.add_partner_account(payload)
    return jsonify(status=status, message=retval)



'''
Cette API valide une inscription d'un partenaire
'''
@app.route('/myclass/api/valide_partnair_account/<value>', methods=['GET','POST'])
@crossdomain(origin='*')
def valide_partnair_account(value):

    print(" ### validation du compte = ",value)
    result, token = pa.valide_partnair_account(value)

    if result:
        #return jsonify(status='True', message='Votre compte a été activé')
        return "Votre Compte a été activé, le token est : "+str(token)
    return jsonify(status='False')


'''
Cette fonction modifie/MAJ un partenaire

'''
@app.route('/myclass/api/update_partner_account/', methods=['POST','GET'])
@crossdomain(origin='*')
def update_partner_account():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = pa.update_partner_account(payload)

    return jsonify(status=status, message=retval)


'''
Cette fonction recupere les données d'un partenaire

'''
@app.route('/myclass/api/get_partner_account/', methods=['POST','GET'])
@crossdomain(origin='*')
def get_partner_account():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = pa.get_partner_account(payload)
    return jsonify(status=status, message=retval)



'''
Cette API index la base donnée.
La fonction "ela_index_all_classes" va aller chercher chaque cours dans la BDD
et créer les mots clées qui sont ensuite enregister dans la table "elaindex" 

'''
@app.route('/myclass/api/ela_index_all_classes/', methods=['POST','GET'])
@crossdomain(origin='*')
def ela_index_all_classes():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = ela_index_class.ela_index_all_classes()
    return jsonify(status=status, message=retval)


'''
Cette API index la base donnée en se basant sur le title.
La fonction "ela_index_all_classes" va aller chercher chaque cours dans la BDD
et créer les mots clées qui sont ensuite enregister dans la table "elaindex" 

'''
@app.route('/myclass/api/ela_index_all_classes_title/', methods=['POST','GET'])
@crossdomain(origin='*')
def ela_index_all_classes_title():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = ela_index_class.ela_index_all_classes_title()
    return jsonify(status=status, message=retval)

'''
Cette API index la base donnée en se basant sur le description.
La fonction "ela_index_all_classes" va aller chercher chaque cours dans la BDD
et créer les mots clées qui sont ensuite enregister dans la table "elaindex" 

'''
@app.route('/myclass/api/ela_index_all_classes_desc/', methods=['POST','GET'])
@crossdomain(origin='*')
def ela_index_all_classes_desc():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = ela_index_class.ela_index_all_classes_desc()
    return jsonify(status=status, message=retval)



'''
Cette API index la base donnée en se basant sur le objectif.
La fonction "ela_index_all_classes" va aller chercher chaque cours dans la BDD
et créer les mots clées qui sont ensuite enregister dans la table "elaindex" 

'''
@app.route('/myclass/api/ela_index_all_classes_obj/', methods=['POST','GET'])
@crossdomain(origin='*')
def ela_index_all_classes_obj():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = ela_index_class.ela_index_all_classes_obj()
    return jsonify(status=status, message=retval)





'''
Cette API, utilisée dans phase de developpement
est utilisé pour supprimer le token d'un user

Use case : Uniquement en developpement
'''
@app.route('/myclass/api/Dev_del_user_token/', methods=['POST','GET'])
@crossdomain(origin='*')
def Dev_del_user_token():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = dev_function.Dev_del_user_token(payload)
    return jsonify(status=status, message=retval)

'''
Recherche en mode tips
'''
@app.route('/myclass/api/recherche_tips/', methods=['POST','GET'])
@crossdomain(origin='*')
def recherche_tips():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = wp.recherche_tips(payload)
    return jsonify(status=status, message=retval)



'''
Recuperation de l'historique de recherche d'un user
'''
@app.route('/myclass/api/get_stored_recherche/', methods=['POST','GET'])
@crossdomain(origin='*')
def get_stored_recherche():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = wp.get_stored_recherche(payload)
    return jsonify(status=status, message=retval)


'''
Cette API met à jour le password d'un user
'''
'''
Recuperation de l'historique de recherche d'un user
'''
@app.route('/myclass/api/change_uer_pwd/', methods=['POST','GET'])
@crossdomain(origin='*')
def change_uer_pwd():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = eua.change_uer_pwd(payload)
    return jsonify(status=status, message=retval)



'''
Cette API met à jour le l'adresse email principale d'un user
'''

@app.route('/myclass/api/change_uer_email/', methods=['POST','GET'])
@crossdomain(origin='*')
def change_uer_email():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = eua.change_uer_email(payload)
    return jsonify(status=status, message=retval)

'''
Cette API supprime un compte utilisateur tout en gardant la cohérence
des information.

Cela revient à :
1 - Anonyser le compte tous les champ identifiants une personne
(['adr_street', 'adr_city', 'adr_zip', 'adr_country', 'mob_phone','link_facebook', 'link_twitter', 'token'])
2 - Bloquer le compte
3 - Desactiver le compte
'''
@app.route('/myclass/api/delete_user_account/', methods=['POST','GET'])
@crossdomain(origin='*')
def delete_user_account():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = eua.delete_user_account(payload)
    return jsonify(status=status, message=retval)



'''
Cette API verrouille le compte d'un utilisateur
Cela revient à mettre le champ : "locked" à 1

'''
@app.route('/myclass/api/lock_user_account/', methods=['POST','GET'])
@crossdomain(origin='*')
def lock_user_account():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = eua.lock_user_account(payload)
    return jsonify(status=status, message=retval)



'''
Cette API desactive le compte d'un utilisateur
Cela revient à mettre le champ : "active" à 0 et "locked" a 1

'''
@app.route('/myclass/api/desable_user_account/', methods=['POST','GET'])
@crossdomain(origin='*')
def desable_user_account():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = eua.desable_user_account(payload)
    return jsonify(status=status, message=retval)


'''
Cette API enregistre le message d'un utilisateur
Par pour la gestion des message de "contactez-nous".
'''
@app.route('/myclass/api/add_user_message/', methods=['POST','GET'])
@crossdomain(origin='*')
def add_user_message():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    status, retval = um.add_user_message(payload)
    return jsonify(status=status, message=retval)



'''
Cette API ajoute des formation en masse
par exemple avec un fichier CSV
'''

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS


@app.route('/myclass/api/add_class_mass/', methods=['POST','GET'])
@crossdomain(origin='*')
def add_class_mass():
    # On recupere le corps (payload) de la requete
    payload = request.form.to_dict()
    print(" ### payload = ",payload)
    print(request.files)

    if request.method == 'POST':
        # Create variable for uploaded file
        f = request.files['File']

        status, retval = cm.add_class_mass(f, app.config['UPLOAD_FOLDER'], payload)

    return jsonify(status=status, message=retval)



if __name__ == '__main__':
    print(" debut api")

    #ls.init_ch()

    #pc.similaire()
    #pc.textdist()
    #pc.test()
    app.run(host='127.0.0.1', port=5000, debug=True)
    #app.run(host='192.168.0.21', port=5000, debug=True)
