from array import array
import threading
from flask import session,Flask,request, jsonify
import flask
from utility.app_logging import logger_name
import logging
import persistence
import Model.isp_model as isp_model
import Model.model_manager as model_manager
from werkzeug.security import check_password_hash
import View.view_privilege as privileges
import Modules.Inventory.inventory_view as inventory_view
from datetime import timedelta
import View.view_error_management as view_error_management
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
from flask_cors import CORS

logger = logging.getLogger(logger_name + ".VIEW")

__app__ = Flask("OpenIsp")
__app__.secret_key = "aseqzdwxc"
__app__.permanent_session_lifetime = timedelta(minutes=2)
__app__.logger = logger
#CORS(__app__)

__resource_array__ : array
__id_counter__ : int = 1


limiter = Limiter(__app__,key_func=get_remote_address,default_limits=["500 per minute"])
limiter.logger = logger


from werkzeug.serving import make_server
class ServerThread(threading.Thread):

    def __init__(self, app,ip,port):
        threading.Thread.__init__(self)
        self.server = make_server(ip, port, app)
        self.ctx = app.app_context()
        self.ctx.push()

    def run(self):
        logger.info('starting server')
        self.server.serve_forever()

    def shutdown(self):
        self.server.shutdown()

__server_process__ : ServerThread

def get_user_privilege() :
    return privileges.get_privileges_from_user(session["user_account_id"])


def init() :

    @__app__.before_request
    def before_request_func():

        global __id_counter__
        logger.debug("before_request processing")
        logger.debug("request from " + request.remote_addr)
        logger.debug("request header" + str(request.headers.__dict__))

        if request.json :
            logger.debug("request json body : " + str(request.json))


        if not "client_id" in session :
            session["client_id"] = str(__id_counter__)
        logger.debug("client_id is " + session["client_id"])
        __id_counter__ = __id_counter__ + 1


        if not request.path == "/api/login" and not "username" in session :
            logger.warning("Unauthorized client with id " + session["client_id"] + " try to access application")
            resp = jsonify({'message' : 'Unauthorized'})
            resp.status_code = 401
            return resp

        if "username" in session :
            logger.debug("request from  " + session["username"])




    privileges.init()

    view_error_management.define_error_management(__app__)

@__app__.route('/api/login',methods = ['POST'])
def login():
    _json = request.json
    _username = _json['username']
    _password = _json['password']


    with persistence.get_Session_Instance() as sess :

        Item = sess.query(isp_model.user_account).filter(isp_model.user_account.nickname == _username).first()
        if not isinstance(Item,isp_model.user_account) :
            logger.warning("user tried to login with unknown account name : " + _username)
            resp = jsonify({'message' : 'Bad Request - user account not found'})
            resp.status_code = 400
            return resp

        if not check_password_hash(Item.password,_password) :
            logger.warning("user with account name '" + _username + "' tried to login with invalid password")
            resp = jsonify({'message' : 'Bad Request - invalid password for this account'})
            resp.status_code = 400
            return resp



        session["username"] = _username
        session["user_account_id"] = Item.id
        logger.info("account " + _username + " logged IN successfully with id : " + session["client_id"])
        resp = jsonify({'message' : 'login successful'})
        resp.status_code = 200
        return resp


@__app__.route('/api/logout',methods = ['POST'])
def logout():
    logger.info("account " + session["username"] + " logged OUT with id : " + session["client_id"])
    session.clear()
    return jsonify('logout')


@__app__.route('/routes',methods = ['GET'])
@privileges.manager.require_authorization(required_role=inventory_view.inventory_admin_role,get_privilege_func=get_user_privilege)
def routes():
    routes = []
    for route in __app__.url_map.iter_rules():
        routes.append('%s' % route)
    return jsonify(routes)


@__app__.after_request
def after_request(response):
    header = response.headers
    header['Access-Control-Allow-Origin'] = '*'
    header['Access-Control-Allow-Methods'] = 'GET,HEAD,OPTIONS,POST,PUT'
    header['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Authorization'
    return response


def run() :
    global __server_process__
    __server_process__ = ServerThread(__app__,"0.0.0.0",8000)
    __server_process__.start()
    logger.info('View server started')



def stop() :
    global __server_process__
    __server_process__.shutdown()
    logger.info('View server stopped')


def add_blueprint(blueprint : flask.Blueprint) :
    __app__.register_blueprint(blueprint)

@privileges.manager.require_authorization(required_role=inventory_view.inventory_read_only_role,get_privilege_func=get_user_privilege)
def tab():
    return jsonify([2,5,7])


__app__.add_url_rule("/tab","/tab",tab)
