from xml.etree import cElementTree as eTree

from typing import (
    Dict,
    List,
    Union,
)

import sysactions

from helper import remove_accents
from old_helper import F, get_sale_line_priced_items, round_half_away_from_zero

from common import PrinterCommon
from printer import simplify_sale_line_elements
from _AposA8PrintLine import AposA8PrintLine
from _AposA8Align import AposA8Align
from _AposA8CommandType import AposA8CommandType
from _AposA8Constants import AposA8Constants


APOS_DASH = AposA8PrintLine(AposA8Align.CENTER, AposA8Constants.SEPARATOR_DASH, AposA8CommandType.PRINT_TEXT)
APOS_NEWLINE = AposA8PrintLine(AposA8Align.CENTER, "", AposA8CommandType.PRINT_TEXT)
APOS_HASH = AposA8PrintLine(AposA8Align.CENTER, AposA8Constants.SEPARATOR_HASH, AposA8CommandType.PRINT_TEXT)


def add_loyalty_custom_text(report, order, custom_text):
    # type: (list, eTree.Element, dict) -> None
    loyalty_user_name = order.find("CustomOrderProperties/OrderProperty[@key='CUSTOMER_NAME']")
    loyalty_user_cpf = order.find("CustomOrderProperties/OrderProperty[@key='LOYALTY_SYSTEM_USER_CPF']")

    if loyalty_user_name is not None and loyalty_user_cpf is not None:
        name_and_cpf = custom_text["name_cpf"].format(nome_cliente=loyalty_user_name.get("value"),
                                                      cpf_cliente=loyalty_user_cpf.get("value"))
        report.append(AposA8PrintLine(AposA8Align.CENTER, name_and_cpf, AposA8CommandType.PRINT_TEXT))
    elif loyalty_user_cpf is not None:
        cpf = custom_text["cpf"].format(cpf_cliente=loyalty_user_cpf.get("value"))
        report.append(AposA8PrintLine(AposA8Align.CENTER, cpf, AposA8CommandType.PRINT_TEXT))
    else:
        non_participating = custom_text["non_participating"]
        report.append(AposA8PrintLine(AposA8Align.CENTER, non_participating, AposA8CommandType.PRINT_TEXT))

    report.append(APOS_NEWLINE)
    report.append(APOS_DASH)
    report.append(APOS_NEWLINE)


def append_items_header(report):
    product_header = "COD     DESCR          QTD UN    VL UNIT   TOTAL"
    report.append(AposA8PrintLine(AposA8Align.CENTER, product_header, AposA8CommandType.PRINT_TEXT))


def append_and_count_sale_items(
    report,             # type: List
    order,              # type: eTree
    printer_common      # type: PrinterCommon
):
    # type: (...) -> int

    items_amount = 0

    sale_lines = simplify_sale_line_elements(order.findall("SaleLine"))
    sale_lines = get_sale_line_priced_items(sale_lines)

    for line in sale_lines:
        line_params = _get_line_params(line)
        item_price, multiplied_qty, name, part_code, level = line_params
        measure_unit = line.get("measureUnit") if "measureUnit" in line.attrib else "un"
        items_amount += 1
        quantity = F(multiplied_qty)
        item_value = round_half_away_from_zero(F(item_price) / quantity, 2)
        line = "%-7.7s %-14.14s%6.3f%-3.2s%9.2f" % (part_code, name, quantity, measure_unit, item_value)
        string = ("%-5.40s %7.02f" % (line, F(item_price)))

        report.append(AposA8PrintLine(AposA8Align.CENTER, string, AposA8CommandType.PRINT_TEXT))

    if float(order.get("tip", 0)) > 0:
        tips_lines = printer_common.get_tip_order(order, is_mobile=True)
        items_amount += len(tips_lines.split("\n")) - 1
        report.append(AposA8PrintLine(AposA8Align.CENTER, tips_lines, AposA8CommandType.PRINT_TEXT))

    return items_amount


def _get_line_params(
        line    # type: eTree
):
    # type: (...) -> Union[list, List[str]]

    return map(
                line.get,
                (
                    "itemPrice",
                    "multipliedQty",
                    "productName",
                    "partCode",
                    "level"
                )
        )

def append_tax_data(report, total_taxes):
    approx_value_text = "Valor aproximado dos tributos deste cupom"
    report.append(AposA8PrintLine(AposA8Align.LEFT, approx_value_text, AposA8CommandType.PRINT_TEXT))

    nacional_federal_value = total_taxes['nacionalfederal']['value']
    estadual_value = total_taxes['estadual']['value']

    total_tax_value = float(nacional_federal_value) + float(estadual_value)
    report.append(AposA8PrintLine(AposA8Align.RIGHT, "R$%7.2f" % total_tax_value, AposA8CommandType.PRINT_TEXT))

    nacional_federal_percent = total_taxes['nacionalfederal']['percent']
    estadual_percent = total_taxes['estadual']['percent']

    federal_tax = "Fed = R$%7.2f (%.2f%%), Est = R$%7.2f (%.2f%%)" % (
        nacional_federal_value,
        nacional_federal_percent,
        estadual_value,
        estadual_percent
    )
    report.append(AposA8PrintLine(AposA8Align.CENTER, federal_tax, AposA8CommandType.PRINT_TEXT))

    law_cite = "(Conforme Lei Fed. 12.741/2012)"
    report.append(AposA8PrintLine(AposA8Align.CENTER, law_cite, AposA8CommandType.PRINT_TEXT))

    report.append(APOS_DASH)


def append_coupon_fiscal_parameters(
    coupon_fiscal_parameters,   # type: Dict[str, bool]
    report,                     # type: List
    order,                      # type: eTree.Element
):
    # type: (...) -> None

    if not any(coupon_fiscal_parameters.values()):
        return

    coupon_fiscal_text = []
    if coupon_fiscal_parameters["operator"]:
        user_id = order.get("sessionId").split("user=")[1].split(",")[0]
        coupon_fiscal_text.append("Operador: {}".format(user_id))

    if coupon_fiscal_parameters["order_or_table"]:
        order_id = order.get("orderId")
        table_property = order.find("CustomOrderProperties/OrderProperty[@key='TABLE_NAME']")
        table_name = table_property.get("value") if table_property is not None else ''
        table_name = table_name[:15] + "..." if len(table_name) > 15 else table_name
        if table_name:
            coupon_fiscal_text.append("Pedido/Mesa: {}/{}".format(order_id[-4:], table_name))
        else:
            coupon_fiscal_text.append("Pedido: {}".format(order_id[-4:]))

    if coupon_fiscal_parameters["pos_id"]:
        pos_id = order.get("posId")
        coupon_fiscal_text.append("POS ID: {}".format(pos_id))

    if len(coupon_fiscal_text) > 0:
        report.append(AposA8PrintLine(
                    align=AposA8Align.CENTER,
                    text=" / ".join(coupon_fiscal_text) + "\n",
                    command_type=AposA8CommandType.PRINT_TEXT,
        ))

    report.append(
        AposA8PrintLine(
            align=AposA8Align.CENTER,
            text=AposA8Constants.SEPARATOR_HASH,
            command_type=AposA8CommandType.PRINT_TEXT
        )
    )


def append_customer_name(
    model,                          # type: eTree
    print_customer_name,            # type: str
    report,                         # type: List
    order,                          # type: eTree
    customer_name,                  # type: str
    font_size_withdrawal_panel,     # type: str
):
    # type: (...) -> None

    if not print_customer_name:
        return

    char_amount = 21
    content = (customer_name or '')[:(char_amount - 2)] or order.get('orderId')[-3:]
    report.append(APOS_HASH)

    panel_call_text = remove_accents(
        sysactions.translate_message(
            model=model,
            message_key="YOU_WILL_BE_CALLED",
        )
    )

    report.append(
        AposA8PrintLine(
            align=AposA8Align.CENTER,
            text=panel_call_text,
            command_type=AposA8CommandType.PRINT_TEXT,
            font_size=font_size_withdrawal_panel,
            bold=True,
        )
    )

    report.append(
        AposA8PrintLine(
            align=AposA8Align.CENTER,
            text=content.upper(),
            command_type=AposA8CommandType.PRINT_TEXT,
            font_size=font_size_withdrawal_panel,
            bold=True,
        )
    )

    report.append(APOS_HASH)
