import json
import logging
import datetime
import operator
from functools import reduce

from flask import Blueprint, request
from flask_jwt_extended import jwt_required

from median.models import Magasin, \
    WorkItemModel, Product, ListeItemModel, ListeModel

from common.status import HTTP_200_OK
from peewee import fn

logger = logging.getLogger('median.inventory')
inventory_blueprint = Blueprint('inventory', __name__)


@inventory_blueprint.route('all', methods=['POST'])
@jwt_required()
def get_all():
    data = json.loads(request.data)
    criterias = data.get('criterias', [])
    equipments = data.get('equipments', [])
    expr = (ListeModel.mode == 'I')

    if len(criterias) > 0:
        lst = list(map(lambda s: (
            (ListeModel.liste.contains(s.strip())) |
            (Magasin.libelle.contains(s.strip()))
        ), criterias))

        search = reduce(operator.and_, lst)

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

    if len(equipments) > 0:
        expr = expr & (ListeModel.zone_fin << equipments)

    inventories = ListeModel.select(
          ListeModel.liste, Magasin.libelle, ListeModel.date_creation, Magasin.pk,
          ListeModel.pk, ListeModel.etat, ListeModel.date_modification
    ).join(
          Magasin, on=ListeModel.zone_fin == Magasin.type_mag
    ).where(expr).order_by(-ListeModel.date_creation)

    return {
        'list': [{
                'pk': lst.pk,
                'label': lst.liste,
                'state': lst.etat,
                'equipment': {
                    'label': lst.magasin.libelle,
                    'pk': lst.magasin.pk
                },
                'creationDate': datetime.datetime.utcfromtimestamp(lst.date_creation.timestamp()),
                'modificationDate': datetime.datetime.utcfromtimestamp(lst.date_modification.timestamp())
        } for lst in inventories]
    }, HTTP_200_OK


@inventory_blueprint.route('detail/<string:pk>', methods=['POST'])
@jwt_required()
def get_inventory_detail(pk):
    item = WorkItemModel.select(
         WorkItemModel.lot,
         fn.SUM(WorkItemModel.quantite_dem).alias('quantity')
    ).where(
         WorkItemModel.pk_item == pk
    ).group_by(WorkItemModel.lot)

    return {
        'list': [{
                'batch_num': item.lot,
                'quantity': item.quantity,
            } for item in item.objects()
        ],
    }, HTTP_200_OK


@inventory_blueprint.route('<string:pk>', methods=['POST'])
@jwt_required()
def get_inventory(pk):
    criterias = []
    expr = (ListeModel.pk == pk)

    if len(criterias) > 0:
        lst = list(map(lambda s: (
            (ListeModel.liste.contains(s.strip())) |
            (Magasin.libelle.contains(s.strip()))
        ), criterias))

        search = reduce(operator.and_, lst)

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

    inventories_stock = ListeItemModel.select(
          ListeItemModel.reference, ListeItemModel.fraction,
          ListeItemModel.qte_dem.alias('quantity'),
          ListeItemModel.qte_serv.alias('quantity_equipment'),
          ListeItemModel.pk,
          ListeItemModel.etat,
          ListeItemModel.item,
          ListeItemModel.cip,
          Product.designation.alias('designation')
        ).join(
            ListeModel, on=((ListeItemModel.liste == ListeModel.liste) & (ListeItemModel.mode == ListeModel.mode))
        ).switch(
            ListeItemModel
        ).join(
            Product, on=Product.reference == ListeItemModel.reference
        ).where(expr).order_by(ListeItemModel.item)
    # logger.debug(inventories_stock)
    return {
        'list': [
            {
                'pk': item.pk,
                'item': item.item,
                'quantity': item.quantity,
                'state': item.etat,
                'reference': item.reference,
                'fraction': item.fraction,
                'label': item.designation,
                'quantity_equipment': item.quantity_equipment or 0,
                'gtin': item.cip,
            } for item in inventories_stock.objects()
        ],

    }, HTTP_200_OK
