import json
import logging
import operator
import os
import uuid
from functools import reduce

from flask import Blueprint, request, send_file
from flask_jwt_extended import jwt_required
from marshmallow import Schema, fields
from median.models import Peigne, Service
from peewee import DoesNotExist, JOIN
from ressources.astus.utils import generate_excel_file

from common.status import HTTP_200_OK, HTTP_204_NO_CONTENT, HTTP_500_INTERNAL_SERVER_ERROR

peignes_blueprint = Blueprint('peignes', __name__)

logger = logging.getLogger('median')


def get_all_peignes(args):
    v_search = args['search'] if ('search' in args) else None
    logger.info("Récupérer les peignes")

    andexpr = True
    if v_search is None:
        v_search = ''

    if len(v_search) > 0:

        lst = list(map(lambda s: (
            (Peigne.type_peigne.startswith(s.strip()))
        ), v_search))
        search = reduce(operator.and_, lst)

        expr = reduce(operator.and_, [andexpr, search])
    else:
        expr = andexpr

    total_peignes_count = Peigne.select()\
        .where(expr)\
        .order_by(Peigne.type_peigne)

    return total_peignes_count


def get_obj_peignes(i):
    return {
        'pk': i.pk,
        'label': i.libelle,
        'typePeigne': i.type_peigne,
        'nbPilulier': i.nb_pilulier,
        'taille': i.taille,
        'alveole': i.alveole

    }


class PeigneSchema(Schema):
    pk = fields.Int()
    typePeigne = fields.Int()
    nbPilulier = fields.Int()
    taille = fields.Int()
    alveole = fields.Int()
    label = fields.Str()


schema = PeigneSchema()


@peignes_blueprint.route('', methods=['put'])
def update_peigne():
    args = schema.load(request.json)
    pk = args.get('pk', None)

    peigne = Peigne.select() \
        .where(Peigne.pk == pk) \
        .get()

    peigne.type_peigne = args['typePeigne']
    peigne.nb_pilulier = args['nbPilulier']
    peigne.taille = args['taille']
    peigne.alveole = args['alveole']
    peigne.libelle = args.get('label', '')
    peigne.save()

    return {
        'data': get_obj_peignes(peigne)
    }, HTTP_200_OK


@peignes_blueprint.route('<string:peigne_pk>', methods=['delete'])
def delete_peigne(peigne_pk):
    peigne = Peigne.select(Peigne, Service) \
        .join(Service, JOIN.LEFT_OUTER, on=(Service.type_peigne == Peigne.type_peigne)) \
        .where(Peigne.pk == peigne_pk) \
        .get()

    if not hasattr(peigne, 'service'):
        peigne.delete()
        return {
        }, HTTP_204_NO_CONTENT
    else:
        return {
            'alertMessage': 'peigne.delete.error.exist',
            'param': [peigne.service.libelle]
        }, HTTP_500_INTERNAL_SERVER_ERROR


@peignes_blueprint.route('', methods=['post'])
def create_peigne():
    args = schema.load(request.json)

    try:
        peigne = Peigne.select(Peigne, Service) \
            .join(Service, JOIN.LEFT_OUTER, on=(Service.type_peigne == Peigne.type_peigne)) \
            .where(Peigne.type_peigne == args['typePeigne']) \
            .get()

        return {
            'alertMessage': 'peigne.create.error.exist',
            'param': [peigne.type_peigne]
        },  HTTP_500_INTERNAL_SERVER_ERROR

    except DoesNotExist:
        peigne = Peigne()
        peigne.type_peigne = args['typePeigne']
        peigne.nb_pilulier = args['nbPilulier']
        peigne.taille = args['taille']
        peigne.alveole = args['alveole']
        peigne.libelle = args.get('label', '')
        peigne.save()

        return {
            'data': get_obj_peignes(peigne)
        }, HTTP_200_OK


@peignes_blueprint.route('all', methods=['POST'])
@jwt_required()
def get_locations():
    try:
        args = json.loads(request.data)
        total_peignes_count = get_all_peignes(args)
        paged_emplacements = total_peignes_count

        list_peignes = []

        for peigne in paged_emplacements:
            list_peignes.append(get_obj_peignes(peigne))

        return {
            'data': list_peignes,
            'recordsTotal': total_peignes_count.count(),
        }

    except DoesNotExist:
        logger.error('Get reappro items Datatables raised a DoesNotExist exception')
        return {
            'data': [],
            'recordsTotal': 0,
        }
    except AttributeError as e:
        logger.error(('get all prescription raised an exception: ', e.args))
        return {
            'data': [],
            'recordsTotal': 0,
            'recordsFiltered': 0,
            'error': 'filterByMagasin missing from the request'
        }
    except Exception as error:
        logger.error(('Datatables emplacements raised an exception: ', error.args))
        return {
            'data': [],
            'recordsTotal': 0,
            'error': error.args
        }


@peignes_blueprint.route('export', methods=['PATCH'])
@jwt_required()
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_peignes(data)
    generate_excel_file(name, headers, stocks, get_obj_peignes())

    return send_file(name, as_attachment=True)
