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

from flask import Blueprint, request
from flask_jwt_extended import jwt_required
from median.models import HistoriqueBlocage, CodeBlocage, Product, Magasin
from peewee import fn, JOIN
from common.status import HTTP_200_OK

blocked_history_blueprint = Blueprint('blocked_history', __name__)


@blocked_history_blueprint.route('count', methods=['POST'])
@jwt_required()
def count():
    res = get_history_request().count()
    return {
        "data": res
    }, HTTP_200_OK


@blocked_history_blueprint.route('equipments', methods=['POST'])
@jwt_required()
def get_equipment():
    req = (Magasin.select(Magasin.pk, Magasin.libelle, Magasin.mag, Magasin.avatar, Magasin.eco_type)
           .join(HistoriqueBlocage, on=Magasin.mag == fn.SUBSTRING(HistoriqueBlocage.adresse, 1, 3))
           .join(Product, JOIN.LEFT_OUTER, on=HistoriqueBlocage.reference == Product.reference)
           .where(get_where_expression())
           .group_by(Magasin.pk))

    return {
        "list": [{
            'pk': item.pk,
            'label': item.libelle,
            'avatar': item.avatar,
            'mag': item.mag,
            'eco_type': item.eco_type
        } for item in req]
    }, HTTP_200_OK


def get_where_expression():
    data = json.loads(request.data)

    search_list = data.get('criterias', [])
    start = data['start']
    end = data['end']

    andexpr = (HistoriqueBlocage.chrono >= start) & (HistoriqueBlocage.chrono <= end)

    if len(search_list) > 0:
        search = list(map(lambda s: (
            (fn.LOWER(HistoriqueBlocage.adresse).contains(s.lower().strip())) |
            (fn.LOWER(Product.designation).contains(s.lower().strip())) |
            (fn.LOWER(Product.reference).contains(s.lower().strip())) |
            (fn.LOWER(HistoriqueBlocage.ucd).contains(s.lower().strip()))
        ), search_list))
        search = reduce(operator.and_, search)
        expr = reduce(operator.and_, [andexpr, search])
    else:
        expr = andexpr

    return expr


def get_history_request():
    andexpr = get_where_expression()
    data = json.loads(request.data)
    equipments = data.get('equipments', [])

    search = (Magasin.pk << equipments)
    andexpr = reduce(operator.and_, [andexpr, search])

    return (HistoriqueBlocage
            .select(
                HistoriqueBlocage.chrono.alias('chrono'),
                HistoriqueBlocage.adresse.alias('adresse'),
                HistoriqueBlocage.reference.alias('reference'),
                HistoriqueBlocage.pk.alias('pk'),
                HistoriqueBlocage.fraction.alias('fraction'),
                HistoriqueBlocage.bloque.alias('bloque'),
                HistoriqueBlocage.ucd.alias('ucd'),
                HistoriqueBlocage.lot.alias('lot'),
                Magasin.libelle.alias('equipment_label'),
                Magasin.eco_type.alias('equipment_eco_type'),
                CodeBlocage.libelle.alias('designation'),
                Product.designation.alias('ref_designation'),
                HistoriqueBlocage.datalu.alias('data'))
            .join(CodeBlocage, JOIN.LEFT_OUTER, on=HistoriqueBlocage.bloque == CodeBlocage.valeur)
            .join(Product, JOIN.LEFT_OUTER, on=HistoriqueBlocage.reference == Product.reference)
            .join(Magasin, on=Magasin.mag == fn.SUBSTRING(HistoriqueBlocage.adresse, 1, 3))
            .where(andexpr)
            .order_by(HistoriqueBlocage.chrono.desc()))


@blocked_history_blueprint.route('all', methods=['POST'])
@jwt_required()
def get():
    data = json.loads(request.data)

    page = data.get('page', -1)
    page_size = data.get('pageSize', -1)

    history = get_history_request().limit(page_size).offset(page * page_size)

    return {
        "list": [{
            "pk": item.pk,
            "adress": item.adresse,
            "data": item.data,
            "code": item.bloque,
            "equipement": {
                'label': item.equipment_label,
                'eco_type': item.equipment_eco_type
            },
            "product": {
                "reference": item.reference,
                "label": item.ref_designation.strip() if item.ref_designation is not None else '',
                "fraction": item.fraction,
                "batch_number": item.lot,
            } if item.ref_designation is not None else None,
            "chrono": datetime.utcfromtimestamp(item.chrono.timestamp()),
            "bloque": 'blocked.reason.unknown' if item.designation is None else item.designation,
            "comment": None

        } for item in history.objects()]
    }, HTTP_200_OK

# @blocked_history.route('<string:site_pk>', methods=['GET'])
# @jwt_required()
# def get_equipments(site_pk):
#     item = (Site
#             .select(Site.code, Site.label, Site.country_code, Site.pk)
#             .where(Site.pk == site_pk).get())
#
#     return {
#         "data": {
#             "pk": item.pk,
#             "code": item.code,
#             "label": item.label,
#             "country_code": item.country_code,
#             "equipments": [{
#                 "pk": equipement.pk,
#                 "code": equipement.code,
#                 "family": equipement.familly,
#                 "type": equipement.type,
#                 "status": equipement.status,
#             } for equipement in item.equipments]
#         }
#     }, 200
