import base64
import json
from xml.etree import cElementTree as eTree

import sysactions
from modelcommon.printer import SeparatorTag
from msgbus import (
    FM_PARAM,
    TK_PRN_PRINT
)
from sysactions import (
    get_storewide_config,
    get_model,
    get_current_order,
    show_confirmation,
    get_podtype
)
from typing import (
    Dict,
    Optional
)
from utilfunctions import get_device_service


class PrintReceipt(object):
    def __init__(self, mb_context, logger):
        self.mb_context = mb_context
        self.logger = logger

        self.print_merchant_receipt = self._get_store_config("Store.PrintMerchantReceipt", "False")
        self.print_customer_receipt = self._get_store_config("Store.PrintCustomerReceipt", "False")
        self.ask_print_customer_receipt = self._get_store_config("Store.AskPrintCustomerReceipt", "True")

    @staticmethod
    def _get_store_config(
        config,         # type: str
        default_value,  # type: str
    ):
        # type: (...) -> bool

        return get_storewide_config(config, defval=default_value).lower() == "true"

    def print_tef_receipts(
        self,
        pos_id,                 # type: str
        fiscalization_type="",  # type: Optional[str]
        cancel_receipt=False    # type: Optional[bool]
    ):
        # type: (...) -> None

        try:
            model = get_model(pos_id)
            order_id = get_current_order(model).get("orderId")
            order_taker = sysactions.get_posot(model)
            order_pict = order_taker.orderPicture(orderid=order_id)
            order = eTree.XML(order_pict).find("Order")
            tenders = order.findall("TenderHistory/Tender")
            print_customer_receipt_response = None

            sector_name = None
            sector = order.find(".//CustomOrderProperties/OrderProperty[@key='{}']".format("SECTOR"))
            if sector is not None:
                sector_name = sector.get("value", None)

            for tender in tenders:
                if int(tender.get("eletronicType")) not in (0, 9):
                    tender_detail = json.loads(tender.get("tenderDetail"))
                    print_customer_receipt_response = self.print_tef_tender_receipt(
                        pos_id=pos_id,
                        tender_detail=tender_detail,
                        fiscalization_type=fiscalization_type,
                        cancel_receipt=cancel_receipt,
                        print_customer_receipt=print_customer_receipt_response,
                        sector=sector_name,
                    )
        except Exception:  # noqa
            self.logger.exception("Error printing TEF receipts")

    def print_tef_tender_receipt(
        self,
        pos_id,                         # type: str
        tender_detail,                  # type: Dict
        fiscalization_type="",          # type: Optional[str]
        cancel_receipt=False,           # type: Optional[bool]
        print_customer_receipt=None,    # type: Optional[bool]
        sector=None,                    # type: str
    ):
        # type: (...) -> Optional[bool]

        container = tender_detail.get("ReceiptCancel", {}) if cancel_receipt else tender_detail
        has_merchant_receipt = "ReceiptMerchant" in container and container["ReceiptMerchant"] not in ['', None]
        has_customer_receipt = "ReceiptCustomer" in container and container["ReceiptCustomer"] not in ['', None]

        if not (has_merchant_receipt or has_customer_receipt):
            return

        try:
            model = get_model(pos_id)
            pod_type = get_podtype(model)
            current_printer = get_device_service(
                pos_id=pos_id,
                device_type="printer",
                sector=sector,
            )

            if has_merchant_receipt and self.print_merchant_receipt and pod_type != "TT":
                self._print_tender_receipt(
                    current_printer,
                    container["ReceiptMerchant"],
                    fiscalization_type=fiscalization_type
                )

            if has_customer_receipt:
                if self.ask_print_customer_receipt:
                    if print_customer_receipt is None:
                        print_customer_receipt = show_confirmation(pos_id, "$WANT_TO_PRINT_CUSTOMER_RECEIPT")
                else:
                    print_customer_receipt = self.print_customer_receipt

                if print_customer_receipt:
                    self._print_tender_receipt(
                        current_printer,
                        container["ReceiptCustomer"],
                        fiscalization_type=fiscalization_type
                    )
        except Exception:  # noqa
            self.logger.exception("Error printing TEF receipt for tender")

        return print_customer_receipt

    def _print_tender_receipt(
        self,
        current_printer,    # type: str
        receipt_data,       # type: str
        fiscalization_type=""       # type: Optional[str]
    ):
        # type: (...) -> None

        receipt = self._decode_receipt(
            receipt_data,
            fiscalization_type
        )
        self.mb_context.MB_EasySendMessage(
            current_printer,
            TK_PRN_PRINT,
            FM_PARAM,
            receipt,
            30000000
        )

    @staticmethod
    def _decode_receipt(
        receipt_data,           # type: str
        fiscalization_type      # type: str
    ):
        # type: (...) -> str

        append_cut_command = not fiscalization_type or not fiscalization_type.startswith("APOS")
        cut_tag = b"{}SpaceCutReceiptCard{}"
        space_cut_receipt_card = cut_tag.format(SeparatorTag.start, SeparatorTag.end) if append_cut_command else ""
        receipt = "{}{}".format(
            base64.b64decode(receipt_data),
            space_cut_receipt_card
        )
        return receipt
