import logging
import json
from datetime import datetime

from common.status import HTTP_200_OK, HTTP_400_BAD_REQUEST
from common.templating import render_template
from flask import Blueprint, request, session
from flask_jwt_extended import jwt_required
from median.models import Product, Ucd, Stock, Cip, Config, Printer
from median.views import PrinterView, PrinterViewException
from median.constant import EcoType

logger = logging.getLogger("median.reference")
reference_blueprint = Blueprint('reference', __name__)


def get_obj_acced(ref: Product):
    return {
        'externe': ref.externe,
        'com_med': ref.com_med
    }


def get_obj_astus(ref: Product):
    return {
        'unit_gest': ref.unit_gest,
        'unit_admin': ref.unit_admin,
        'coef_conv': ref.coef_conv,
        'delai_peremp': ref.delai_peremp,
        'multidose_par_uf': ref.multidose_par_uf,
        'conversion_ucd': ref.conversion_ucd,
        'warn_pct': ref.warn_pct,
        'risk': ref.risque,
        'narcotic': ref.stup,
    }


def get_obj_riedl(ref):
    return {
        'condi': ref.condi,
        'forme': ref.forme,
        'cip': ref.cip
    }


@reference_blueprint.route('/synchrocip', methods=['GET'])
@jwt_required()
def get_synchro_cip_info():

    res = (Config.select(Config.propriete, Config.value, Config.hierarchie_menu)
           .where((Config.poste == 'TOUS') &
                  (Config.cle == 'cfg') &
                  (Config.propriete << ['k_synchrocip_date', 'k_synchrocip_fichier_date'])))

    return {
        'data': [
            {
                'property': item.propriete,
                'value': item.value,
                'info': item.hierarchie_menu
            } for item in res
        ]
    }, HTTP_200_OK


def get_obj_external(ref):
    return {
        'qml_cde': ref.qml_cde,
        'qml_serv': ref.qml_serv,

    }


@reference_blueprint.route('/<string:reference_pk>/<string:eco_type>', methods=['PATCH'])
@jwt_required()
def update(reference_pk, eco_type):
    data = json.loads(request.data)

    product: Product = (Product.select(Product)
                        .where(Product.pk == reference_pk).get())

    if eco_type == EcoType.Riedl.value:  # Riedl
        product.condi = data['condi']
        product.forme = data['forme']
        product.cip = data['cip']
        product.save()
    elif eco_type == EcoType.Astus.value:  # Astus
        product.unit_gest = data['unit_gest']
        product.unit_admin = data['unit_admin']
        product.coef_conv = int(data['coef_conv'])
        product.delai_peremp = int(data['delai_peremp'])
        product.multidose_par_uf = data['multidose_par_uf']
        product.conversion_ucd = data['conversion_ucd']
        product.warn_pct = int(data['warn_pct'])
        product.risque = int(data['risk'])
        product.stup = int(data['narcotic'])
        product.save()
    elif eco_type == EcoType.Externe.value:  # External
        product.qml_cde = data.get('qml_cde', 0)
        product.qml_serv = data.get('qml_serv', 0)
        product.save()
    elif eco_type == EcoType.Coupe.value or eco_type == EcoType.Cueillette.value:  # Acced
        product.externe = data.get('externe')
        product.com_med = data.get('com_med', '')
        product.save()

    return {'data': 'success'}, HTTP_200_OK


@reference_blueprint.route('/<string:reference_pk>/<string:eco_type>', methods=['GET'])
@jwt_required()
def get_all(reference_pk, eco_type):
    ref = (Product.select(Product)
           .where(Product.pk == reference_pk).get())

    obj = None
    if eco_type == EcoType.Riedl.value:  # Riedl
        obj = get_obj_riedl(ref)
    elif eco_type == EcoType.Astus.value:  # Astus
        obj = get_obj_astus(ref)
    elif eco_type == EcoType.Externe.value:  # External
        obj = get_obj_external(ref)
    elif eco_type == EcoType.Cueillette.value or eco_type == EcoType.Coupe.value:
        obj = get_obj_acced(ref)

    return {'data': obj
            }, HTTP_200_OK


@reference_blueprint.route('/<string:reference_pk>/ucds', methods=['GET'])
@jwt_required()
def get_ref_ucds(reference_pk):
    req = (Ucd.select(Ucd.pk, Ucd.ucd)
           .join(Product, on=Ucd.reference == Product.reference)
           .where(Product.pk == reference_pk))

    return {'list': [
        {
            'pk': item.pk,
            'label': item.ucd
        } for item in req
    ]}, HTTP_200_OK


@reference_blueprint.route('/<string:reference_pk>/batchs', methods=['GET'])
@jwt_required()
def get_ref_batch(reference_pk):
    req = (Stock.select(Stock.lot.distinct().alias('batch'))
           .join(Product, on=Stock.reference == Product.reference)
           .where(Product.pk == reference_pk))

    return {'list': [
        {
            'batch': item.batch
        } for item in req
    ]}, HTTP_200_OK


@reference_blueprint.route('/<string:reference_pk>/cips', methods=['GET'])
@jwt_required()
def get_ref_cips(reference_pk):
    req = (Cip.select(Cip.cip, Cip.ucd)
           .join(Ucd, on=Ucd.ucd == Cip.ucd)
           .join(Product, on=Ucd.reference == Product.reference)
           .where((Product.pk == reference_pk))
           .group_by(Cip.cip, Cip.ucd))

    return {'list': [
        {

            'cip': item.cip,
            'ucd': item.ucd
        } for item in req
    ]}, HTTP_200_OK


@reference_blueprint.route('/<string:reference_pk>/print', methods=['PUT'])
@jwt_required()
def print_labels(reference_pk):
    """
    Print a drug label
    """
    printer: Printer = None
    try:
        data = json.loads(request.data)
        printer = Printer.get(pk=data['printer_id'])
        product: Product = Product.get(pk=reference_pk)

    except Exception as e:
        return {'message': 'Error when retrieve printer information', 'trace': str(e)}, HTTP_400_BAD_REQUEST

    try:
        datas = {
            "client_header": "Deenova France",
            "product_desig": product.designation,
            "dci": product.dci or "",
            "comment": "",
            "product_gtin": data['cip'],
            "batch": data['batch']['batch'],
            "date_perem": datetime.strptime(data['expirationDate'], "%Y-%m-%d"),
            "fraction": "100",
            "serial": "",
            "quantity": data['quantity']
        }
        with PrinterView(printer, 3, session["user_id"]) as p:
            template, _ = p.printer_template("drug_label")
            rendered_label = render_template(template, datas, {})
            print_result = p.send(rendered_label, f"ref: {product.designation}")
            if not print_result:
                error_msg = f"Failed to print label with serial {product.designation}"
                return {'message': error_msg}, HTTP_400_BAD_REQUEST

    except PrinterViewException as e:
        logger.error(f"PrinterView: {e}")
        return {'message': "Error when try to print the label"}, HTTP_400_BAD_REQUEST

    return data, HTTP_200_OK
