import json
import logging
import os
import uuid

from flask import Blueprint, request, session, send_file, jsonify
from flask_jwt_extended import jwt_required
from median.database import decripte
from median.models import User
from peewee import DoesNotExist
from common.util import mustHaveRights
from common.exception import WebPermissionException

from common.status import HTTP_200_OK, HTTP_400_BAD_REQUEST, HTTP_500_INTERNAL_SERVER_ERROR
from ressources.astus.utils import generate_excel_file

users_blueprint = Blueprint('users', __name__)

logger = logging.getLogger('median')

RESSOURCE_NAME = 'WEB_USERS'


@users_blueprint.errorhandler(WebPermissionException)
def handle_error(err):
    return jsonify(err.to_dict()), err.status_code


def get_all_users():
    user_id = session['user_id']
    calling_user = User.get(pk=user_id)

    users = User.select(
        User.pk, User.username, User.profil, User.password, User.maintenance,
        User.droit_stupefiant, User.email, User.isEnabled, User.login, User.lang, User.avatar
    ).where(
        ((calling_user.profil == "ECO-DEX") | (calling_user.profil == "ADMIN")) |
        ((User.profil != 'ECO-DEX') & (User.profil != 'ADMIN'))
    ).order_by(User.username)

    return users


def get_obj_users(i):
    return {
        'pk': i.pk,
        'login': i.login,
        'user': i.username,
        'profil': i.profil,
        'maintenance': i.maintenance,
        'stupefiant': i.droit_stupefiant,
        'email': i.email,
        'isEnabled': i.isEnabled,
        'lang': i.lang,
        'avatar': i.avatar
    }


@users_blueprint.route('export', methods=['PATCH'])
@jwt_required()
@mustHaveRights(RESSOURCE_NAME, canView=True)
def export():
    data = json.loads(request.data)
    headers = data['headers']

    name = os.sep.join(
        [os.getcwd(), "tmp_export", "%s.xlsx" % uuid.uuid4()])
    stocks = get_all_users()
    generate_excel_file(name, headers, stocks, get_obj_users)

    return send_file(name, as_attachment=True)


@users_blueprint.route('deleteUser', methods=['DELETE'])
@jwt_required()
@mustHaveRights(RESSOURCE_NAME, canEdit=True)
def delete_user():
    """Delete the user by the primary key"""
    data = json.loads(request.data)
    v_pk = data.get('pk', 0)

    try:
        usr = User.get_by_id(v_pk)
        logger.info("Delete user [%s] (%i) by %s" % (usr.username, usr.pk, session['username']))
        usr.delete_instance()
    except DoesNotExist as e:
        return {
            'alertMessage': 'user.delete.error.notexist',
            'param': [e.args]
        }, HTTP_400_BAD_REQUEST

    return {}, HTTP_200_OK


@users_blueprint.route('create', methods=['POST'])
@jwt_required()
@mustHaveRights(RESSOURCE_NAME, canEdit=True)
def create_user():
    try:
        args = json.loads(request.data)
        v_user = args['user']
        v_profil = args['profil']
        v_email = args['email']
        v_maintenance = args.get('maintenance', 0)
        v_stupefiant = args.get('stupefiant', 0)
        v_login = args['login']
        v_lang = args.get('lang', 'en_GB')
        v_test = int(args.get('test', 0))
    except KeyError:
        return {'message': 'User.error.key_missing'}, HTTP_500_INTERNAL_SERVER_ERROR

    if v_test == 1:
        calling_usr = User.get(login='medianweb')
    else:
        calling_usr = User.get(pk=session['user_id'])

    try:
        User.select() \
            .where(
            (((v_user != '') & (User.username == v_user)) |
             ((v_email != '') & (User.email == v_email)) |
             ((v_login != '') & (User.login == v_login)))) \
            .get()
        return {'message': 'User.error.already_exist'}, HTTP_500_INTERNAL_SERVER_ERROR
    except DoesNotExist:

        if not v_email:
            text = v_user.lower().replace(' ', '_')
            c = User.select().where(User.email % f"{text}*").count()
            v_email = f"{text}{c if c > 0 else ''}@medianweb"

        # Only user with 'ECO-DEX', 'PHARMACIEN' or 'ADMIN' can enable/disabled a user
        if calling_usr.profil in ('DEENOVA', 'ECO-DEX', 'PHARMACIEN', 'ADMIN'):
            user = User.create(
                login=v_login,
                username=v_user,
                profil=v_profil,
                maintenance=v_maintenance, droit_stupefiant=v_stupefiant,
                email=v_email, lang=v_lang,
                isEnabled=args.get('isenabled', 1))
        else:
            user = User.create(
                login=v_login,
                username=v_user,
                profil=v_profil,
                maintenance=v_maintenance, droit_stupefiant=v_stupefiant, email=v_email,
                lang=v_lang)
        logger.info('User %s create successfully' % v_user)
        return {
            'id': user.pk,
            'mail': user.email,
            'message': 'User %s create successfully' % v_user,
        }


@users_blueprint.route('', methods=['POST'])
@jwt_required()
@mustHaveRights(RESSOURCE_NAME, canView=True)
def get_users():
    user_id = session['user_id']
    callingUser = User.get(pk=user_id)

    logger.info("Récupérer les utilisateurs")

    try:

        total_users_count = (
            User.select(User.pk).count())

        paged_users = User.select(
            User.pk, User.username, User.profil, User.password, User.maintenance,
            User.droit_stupefiant, User.email, User.isEnabled, User.avatar, User.lang
        ).where(
            ((callingUser.profil == "ECO-DEX") |
             (callingUser.profil == "ADMIN")) |
            ((User.profil != 'ECO-DEX') & (User.profil != 'ADMIN'))
        ).order_by(User.username)

        return {'data': [{
            'pk': i.pk,
            'user': i.username,
            'profil': i.profil,
            'maintenance': i.maintenance,
            'stupefiant': i.droit_stupefiant,
            'email': i.email,
            'isEnabled': i.isEnabled,
            'lang': i.lang,
            'avatar': i.avatar
        } for i in paged_users],
            'recordsFiltered': total_users_count}

    except DoesNotExist:
        logger.error('Get users Datatables raised a DoesNotExist exception')
        return [], 0, 0
    except Exception as error:
        logger.error(('Get users Datatables raised an exception: ', error.args))
        return [], 0, 0, error.args


@users_blueprint.route('<string:id>', methods=['GET'])
@jwt_required()
@mustHaveRights(RESSOURCE_NAME, canView=True)
def get_user(id):
    try:
        usr = User.get(pk=id)

        return {
            'pk': usr.pk,
            'user': usr.username,
            'profil': usr.profil,
            'desc': usr.description,
            'login': usr.login,
            'isEnabled': usr.isEnabled > 0,
            'stupefiant': usr.droit_stupefiant,
            'maintenance': usr.maintenance > 0,
            'email': usr.email,
            'lang': usr.lang,
            'avatar': usr.avatar,
            'badge': usr.badge,
            'pin': decripte(usr.password) if usr.password else ''
        }
    except DoesNotExist:
        return {'message': 'User.error.not_exist'}, HTTP_500_INTERNAL_SERVER_ERROR


@users_blueprint.route('', methods=['PUT'])
@jwt_required()
@mustHaveRights(RESSOURCE_NAME, canEdit=True)
def update_user():
    args = json.loads(request.data)
    v_pk = args['pk']
    v_user = args['user']
    v_profil = args['profil']
    v_email = args['email']
    v_maintenance = args.get('maintenance', 0)
    v_stupefiant = args.get('stupefiant', 0)
    v_login = args['login']
    v_lang = args.get('lang', 'en_GB')

    calling_usr = User.get(pk=session['user_id'])
    try:
        User.select(User).where(
            (User.pk != v_pk) & (
                ((v_user != '') & (User.username == v_user)) |
                ((v_email != '') & (User.email == v_email)) |
                ((v_login != '') & (User.login == v_login))
            )).get()
        return {'message': 'User.error.already_exist'}, HTTP_500_INTERNAL_SERVER_ERROR
    except DoesNotExist:

        if v_email == '':
            text = v_user.lower().replace(' ', '_')
            c = User.select().where(User.email % f"{text}*").count()
            v_email = f"{text}{c if c > 0 else ''}@medianweb"

        # Only user with 'ECO-DEX', 'PHARMACIEN' or 'ADMIN' can enable/disabled a user
        if calling_usr.profil in ('ECO-DEX', 'PHARMACIEN', 'ADMIN'):
            User.update(
                login=v_login,
                username=v_user,
                profil=v_profil,
                maintenance=v_maintenance, droit_stupefiant=v_stupefiant, email=v_email,
                lang=v_lang,
                isEnabled=args.get('isEnabled', 1)).where(User.pk == v_pk).execute()
        else:
            User.update(
                login=v_login,
                username=v_user,
                profil=v_profil,
                maintenance=v_maintenance, droit_stupefiant=v_stupefiant, email=v_email,
                lang=v_lang).where(User.pk == v_pk).execute()
        return {
            'message': 'Update user %s successfull' % v_user,
            'id': v_pk,
            'mail': v_email
        }


@users_blueprint.route('avatar', methods=['POST'])
@jwt_required()
def get_users_avatar():
    args = json.loads(request.data)

    user_pks = args.get('user_pks', None)
    req = User.select(User.username, User.avatar, User.pk).where(User.pk << user_pks)
    return {
        'list': [
            {
                'pk': item.pk,
                'name': item.username,
                'avatar': item.avatar
            } for item in req
        ]
    }, HTTP_200_OK
