# -*- coding: utf-8 -*-

import base64
import json
from xml.etree import ElementTree as eTree
import sysactions
from common import PrinterCommon
from fiscalpersistence import Tender
from msgbus import MBEasyContext
from typing import (
    List,
    Optional,
    Dict,
)

from _AposA8PrintLine import AposA8PrintLine
from _AposA8Align import AposA8Align
from _AposA8CommandType import AposA8CommandType
from _AposA8Constants import AposA8Constants

from printer import FiscalPrinter
from printer_wrapper import insert_space
from clichehelper import ClicheHelper
from _AposA8Helpers import (
    append_and_count_sale_items,
    append_coupon_fiscal_parameters,
    append_customer_name,
)


class SatAposA8FiscalPrinter(FiscalPrinter):
    def __init__(
        self,
        mb_context,                     # type: MBEasyContext
        print_customer_name,            # type: bool
        cliche_helper,                  # type: ClicheHelper
        customer_text_field,            # type: str
        printer_common,                 # type: PrinterCommon
        coupon_fiscal_parameters,       # type: Dict[str, bool]
        font_size_withdrawal_panel,     # type: str
    ):
        # type: (...) -> None

        super(SatAposA8FiscalPrinter, self).__init__(
            mb_context,
            print_customer_name,
            cliche_helper,
            coupon_fiscal_parameters,
        )

        self.customer_text_field = customer_text_field
        self.printer_common = printer_common
        self.cliche_helper = cliche_helper
        self.font_size_withdrawal_panel = font_size_withdrawal_panel

    def print_fiscal(self, posid, order, tenders, fiscal_request, fiscal_response, total_taxes, customer_name, url_sefaz=""):
        # type: (str, eTree.Element, list, eTree.Element, eTree.Element, dict, str, str) -> str
        xml = base64.b64decode(fiscal_request.text.strip())
        parsed_xml = eTree.XML(xml)
        n_c_fe = parsed_xml.find("infCFe/ide/nCFe").text
        model = sysactions.get_model(posid)

        report = self._fiscal_report(order, tenders, fiscal_response, n_c_fe, customer_name, model)

        qr_code = fiscal_response.find("QRCode").text.strip()
        sat_key = fiscal_response.find("satkey").text.strip()
        report.append(AposA8PrintLine(AposA8Align.CENTER, sat_key, AposA8CommandType.PRINT_BAR_CODE))
        report.append(AposA8PrintLine(AposA8Align.CENTER, '', AposA8CommandType.PRINT_BAR_CODE))
        report.append(AposA8PrintLine(AposA8Align.CENTER, qr_code, AposA8CommandType.PRINT_QR_CODE))

        text = "Consulte o QRCode pelo Aplicativo"
        report.append(AposA8PrintLine(AposA8Align.CENTER, text, AposA8CommandType.PRINT_TEXT))
        text = "De olho na nota disponivel"
        report.append(AposA8PrintLine(AposA8Align.CENTER, text, AposA8CommandType.PRINT_TEXT))
        text = "na AppStore (Apple) e Play Store (Android)"
        report.append(AposA8PrintLine(AposA8Align.CENTER, text, AposA8CommandType.PRINT_TEXT))

        report.append(AposA8PrintLine(AposA8Align.CENTER, AposA8Constants.SEPARATOR_DASH, AposA8CommandType.PRINT_TEXT))

        tax_text = "%s %7.2f" % ("Valor aproximado dos tributos deste cupom", (
                    float(total_taxes['nacionalfederal']['value']) + float(total_taxes['estadual']['value'])))
        report.append(AposA8PrintLine(AposA8Align.CENTER,
                                      tax_text,
                                      AposA8CommandType.PRINT_TEXT))

        federal_tax = "Fed = R$%7.2f (%.2f%%), Est = R$%7.2f (%.2f%%)" % (
            total_taxes['nacionalfederal']['value'], total_taxes['nacionalfederal']['percent'],
            total_taxes['estadual']['value'], total_taxes['estadual']['percent'])

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

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

        return json.dumps(report, default=lambda x: x.__dict__)

    def print_cancel(self, posid, data):
        return

    def _cancel_report(self, sat_fiscal_response, nCFe, total):
        return

    def _fiscal_report(self, order, tenders, sat_fiscal_response, nCFe, customer_name, model=None):
        # type: (eTree, List[Tender], eTree.Element, dict, str, str, Optional[eTree]) -> List[AposA8PrintLine]
        report = []

        for line in self.cliche_helper.get_cliche():
            report.append(AposA8PrintLine(AposA8Align.CENTER, line, AposA8CommandType.PRINT_TEXT))
        report.append(AposA8PrintLine(AposA8Align.CENTER, AposA8Constants.SEPARATOR_DASH, AposA8CommandType.PRINT_TEXT))
        report.append(AposA8PrintLine(AposA8Align.CENTER, "EXTRATO No. %s" % nCFe, AposA8CommandType.PRINT_TEXT))
        report.append(AposA8PrintLine(AposA8Align.CENTER, "CUPOM FISCAL ELETRONICO - SAT", AposA8CommandType.PRINT_TEXT))
        report.append(AposA8PrintLine(AposA8Align.CENTER, AposA8Constants.SEPARATOR_DASH, AposA8CommandType.PRINT_TEXT))

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

        order_voided = order.get("state") == "VOIDED"
        items_amount = append_and_count_sale_items(report, order, self.printer_common)

        factor = -1 if order_voided else 1

        report.append(AposA8PrintLine(AposA8Align.CENTER, AposA8Constants.SEPARATOR_DASH, AposA8CommandType.PRINT_TEXT))

        qty_total = "%-36s         %3d" % ("QTD. TOTAL DE ITENS", items_amount)
        report.append(AposA8PrintLine(AposA8Align.CENTER, qty_total, AposA8CommandType.PRINT_TEXT))

        total_amount = "%-36s   R$%7.2f" % ("VALOR TOTAL", float(order.get("totalAmount")) + float(order.get("taxTotal")) + float(order.get("tip", 0)))
        report.append(AposA8PrintLine(AposA8Align.CENTER, total_amount, AposA8CommandType.PRINT_TEXT))

        discount = "%-36s   R$%7.2f" % ("DESCONTO", float(order.get("discountAmount")))
        report.append(AposA8PrintLine(AposA8Align.CENTER, discount, AposA8CommandType.PRINT_TEXT))

        total_payable = "%-36s   R$%7.2f" % ("VALOR A PAGAR",
                                             float(order.get("totalAmount"))
                                             + float(order.get("taxTotal"))
                                             - float(order.get("discountAmount")))
        report.append(AposA8PrintLine(AposA8Align.CENTER, total_payable, AposA8CommandType.PRINT_TEXT))

        payment = "%-36s  %s" % ("FORMA DE PAGAMENTO", "Valor Pago")
        report.append(AposA8PrintLine(AposA8Align.CENTER, payment, AposA8CommandType.PRINT_TEXT))

        for tender in tenders:
            tender_descr = self.get_payment_description(self.mb_context, tender)
            tender_amount = tender.amount
            report.append(AposA8PrintLine(AposA8Align.CENTER, "%-36s   R$%7.2f" % (tender_descr, tender_amount),
                                          AposA8CommandType.PRINT_TEXT))

        # Get "Change" (sixth value of tender tuple) from last tender in tenders
        change = tenders[len(tenders) - 1].change

        if change > 0:
            report.append(AposA8PrintLine(AposA8Align.CENTER, "%-36s   R$%7.2f" % ("Troco", change * factor),
                                          AposA8CommandType.PRINT_TEXT))

        report.append(AposA8PrintLine(AposA8Align.CENTER, AposA8Constants.SEPARATOR_DASH, AposA8CommandType.PRINT_TEXT))

        append_customer_name(
            model=model,
            print_customer_name=self.print_customer_name,
            report=report,
            order=order,
            customer_name=customer_name,
            font_size_withdrawal_panel=self.font_size_withdrawal_panel,
        )

        append_coupon_fiscal_parameters(
            coupon_fiscal_parameters=self.coupon_fiscal_parameters,
            report=report,
            order=order,
        )
        report.append(AposA8PrintLine(AposA8Align.CENTER, AposA8Constants.SEPARATOR_DASH, AposA8CommandType.PRINT_TEXT))

        # Campo de texto customizado exibido na área de informações adicionais
        if self.customer_text_field != "":
            for customer_text in self.customer_text_field.split('\\n'):
                report.append(AposA8PrintLine(AposA8Align.CENTER,
                                              customer_text.replace("\\n", ""),
                                              AposA8CommandType.PRINT_TEXT))
            report.append(
                AposA8PrintLine(AposA8Align.CENTER, AposA8Constants.SEPARATOR_DASH, AposA8CommandType.PRINT_TEXT))

        satk = insert_space(sat_fiscal_response.find("satkey").text.strip(), 4)
        report.append(AposA8PrintLine(AposA8Align.CENTER,
                                      str(satk),
                                      AposA8CommandType.PRINT_TEXT))

        report.append(AposA8PrintLine(AposA8Align.CENTER, AposA8Constants.SEPARATOR_DASH, AposA8CommandType.PRINT_TEXT))

        cpf_cnpj = sat_fiscal_response.find("CustomerCPF").text
        cpf_text = "Consumidor: %s" % ("Nao informado" if not cpf_cnpj else cpf_cnpj)
        report.append(AposA8PrintLine(AposA8Align.CENTER, cpf_text, AposA8CommandType.PRINT_TEXT))

        report.append(AposA8PrintLine(AposA8Align.CENTER,
                                      "SAT No. %s" % sat_fiscal_response.find("satno").text.strip(),
                                      AposA8CommandType.PRINT_TEXT))

        report.append(AposA8PrintLine(AposA8Align.CENTER,
                                      sat_fiscal_response.find("datetime").text.strip(),
                                      AposA8CommandType.PRINT_TEXT))

        return report
