import logging

from model.customexception import ProductNotExistsException
from typing import Optional

from actions.products.get_products import (
    get_product_by_barcode,
    get_product_price_from_cache,
)
from sysactions import (
    get_model,
    get_podtype,
    show_messagebox,
)
from systools import sys_log_exception

logger = logging.getLogger("PosActions")


def sell_product_by_barcode(
    pos_id,                   # type: str
    barcode_number,           # type: str
    check_consistency=False,  # type: Optional[bool]
    received_qty="1",         # type: Optional[str]
):
    # type: (...) -> str

    try:
        from posactions import doSale, doCompleteOption, doChangeQuantity
        if not barcode_number:
            return "False"

        if check_consistency and not _is_a_valid_ean13(barcode=barcode_number):
            logger.info("Barcode {0} is not a Valid EAN13".format(barcode_number))
            ret = show_messagebox(pos_id, "$BARCODE_WRONG", buttons="$OK|$CANCEL")
            if ret == 0:
                return "Clear"
            return "False"

        if str(barcode_number).zfill(13).startswith('2'):
            logger.info("Barcode {0} is a Scale Type Code".format(barcode_number))
            plu, calc_qty = _ticket_from_scale(str(barcode_number), pos_id)
            doCompleteOption(str(pos_id), "1", plu, calc_qty)
        else:
            logger.info("Barcode {0} ".format(barcode_number))
            product_by_barcode = get_product_by_barcode(barcode_number)
            if product_by_barcode:
                if product_by_barcode["ruptured"]:
                    logger.info("Scanned barcode {0} product is ruptured!".format(barcode_number))
                    user_message = "$BARCODE_PRODUCT_RUPTURED|{}".format(product_by_barcode["name"])
                    ret = show_messagebox(pos_id, user_message, buttons="$YES|$NO")
                    if ret != 0:
                        return "Clear"

                doCompleteOption(str(pos_id), "1", product_by_barcode['plu'], received_qty)
            else:
                logger.info("Scanned barcode {0} not found on the product database!".format(barcode_number))
                ret = show_messagebox(pos_id, "$BARCODE_NOT_FOUND|{}".format(barcode_number), buttons="$OK|$CANCEL")
                if ret == 0:
                    return "Clear"
                return "False"
        return "True"
    except ProductNotExistsException:
        return "Clear"
    except Exception as _:
        sys_log_exception("Error on [sell_product_by_barcode]")
        logger.exception("Error on [sell_product_by_barcode]")
        return "False"


def _is_a_valid_ean13(
    barcode,   # type: str
):
    # type: (...) -> bool

    if len(str(barcode)) > 13:
        return False
    
    barcode = list(str(barcode).zfill(13))
    index = 0
    value = 0
    dv = barcode.pop()
    for x in barcode:
        value = value + (int(x) * ((index % 2) * 2 + 1))
        index += 1
    value2 = (((int(value / 10) + 1) * 10) - value) % 10
    if value2 != int(dv):
        return False
    return True


def _ticket_from_scale(
    barcode,   # type: str
    pos_id,    # type: str
):
    # type: (...) -> (str, float)

    from posactions import (
        scale_ticket_mode,
        barcode_pattern_reading,
    )

    try:
        first_x = barcode_pattern_reading.find("X")
        first_0 = barcode_pattern_reading.find("0")
        first_y = barcode_pattern_reading.find("Y")
        first_w = barcode_pattern_reading.find("W")
        plu = int(barcode[first_x:first_0 if first_0 > -1 else first_y])
        param = int(barcode[first_y:first_w])

        if scale_ticket_mode == 'price':
            final_price = float(param) / 100
            price = float(get_product_price_from_cache(plu, pos_id))
            qtd = round((final_price / price), 3)
        else:
            qtd = round(float(param) / 1000, 3)

        return str(plu), qtd
    except ProductNotExistsException as ex:
        logger.info("The product {} in Barcode does not exists".format(ex.message))
        show_messagebox(pos_id, "$PRODUCT_DOES_NOT_EXISTS", "$ERROR")
        raise
