import json

from xml.etree.ElementTree import Element
from xml.etree import cElementTree as eTree

from sysactions import (
    StopAction,
    get_model,
    get_operator_session,
    show_messagebox,
)
from typing import (
    Any,
    List,
    Dict,
    Optional,
    Union,
)

from actions.order import update_tenders
from utilfunctions import get_device_service

NOT_ELECTRONIC_TYPE_ID = (0, 9)


def has_electronic_payment(
    order,                          # type: Optional[Element]
    tender_electronic_type=None,    # type: Optional[int]
):
    # type: (...) -> bool

    if tender_electronic_type is not None:
        return tender_electronic_type != 'NON_ELECTRONIC'

    if not order:
        return False

    tenders = order.findall("TenderHistory/Tender")
    for tender in tenders:
        if _get_electronic_type_id(tender) not in NOT_ELECTRONIC_TYPE_ID:
            return True

    return False


def get_electronic_tenders(
    order,  # type: Element
):
    # type: (...) -> List

    tenders = order.findall("TenderHistory/Tender")
    ret_tenders = []
    for tender in tenders:
        electronic_type = _get_electronic_type_id(tender)
        if electronic_type not in NOT_ELECTRONIC_TYPE_ID:
            ret_tenders.append({
                "id": int(tender.get("tenderId")),
                "type": int(tender.get("tenderType")),
                "amount": tender.get("tenderAmount"),
                "electronicType": electronic_type,
                "detail": json.loads(tender.get("tenderDetail", "{}"))
            })

    return ret_tenders


def _get_electronic_type_id(
    tender,     # type: Element
):
    # type: (...) -> int

    return int(tender.get("electronicType") or tender.get("eletronicType"))


def get_tender_details(
    payment_data,   # type: Dict
):
    # type: (...) -> str

    tender_details = json.dumps({
        "Media": payment_data.get("Media", "").strip(),
        "CNPJAuth": payment_data["CNPJAuth"],
        "TransactionProcessor": payment_data["TransactionProcessor"],
        "Bandeira": payment_data["Bandeira"],
        "IdAuth": payment_data["IdAuth"],
        "AuthCode": payment_data["AuthCode"],
        "ReceiptCustomer": payment_data["ReceiptCustomer"],
        "ReceiptMerchant": payment_data["ReceiptMerchant"],
        "AccreditorSat": payment_data["AccreditorSat"] if "AccreditorSat" in payment_data else None,
        "NfceBrand": payment_data["NfceBrand"] if "NfceBrand" in payment_data else None,
        "NsuHost": payment_data["NsuHost"] if "NsuHost" in payment_data else None,
        "CardNumber": payment_data["CardNumber"] if "CardNumber" in payment_data else None,
        "TransactionIdentifier": payment_data.get("TransactionIdentifier"),
        "OriginalNfceBrand": payment_data["OriginalNfceBrand"] if "OriginalNfceBrand" in payment_data else None
    })

    return tender_details


def check_eft_transaction(
    model,              # type: eTree.XML
    pos_id,             # type: str
    order_id,           # type: str
    eft_xml,            # type: str
    electronic_type,    # type: str
):
    # type: (...) -> None

    if eft_xml is None or eTree.XML(eft_xml).get("Result") != "0":
        if eft_xml is None:
            show_messagebox(pos_id, "$ERROR_PROCESSING_TEF")
            raise StopAction()

        if eft_xml:
            xml = eTree.XML(eft_xml)
            response = xml.get("Result") or "(none)"
            if electronic_type in ["CREDIT_CARD", "DEBIT_CARD"]:
                message = "${}_NOT_PROCESSED|{}".format(electronic_type, response.encode('utf-8'))
                show_messagebox(
                    pos_id,
                    message=message
                )

            raise StopAction()


def get_tender_id(
    all_tenders,                # type: eTree
    is_table_service=False,     # type: Optional[bool]
):
    # type: (...) -> str

    if not is_table_service:
        return ""

    if len(all_tenders) == 0:
        return "1"

    last_tender_id = all_tenders[-1].get("tenderId", 0)
    return str(int(last_tender_id) + 1)


def save_cancel_receipt(
    pos_id,     # type: str
    order,      # type: eTree.XML
    tender_id,  # type: str
    data,       # type: str
):
    # type: (...) -> bool

    new_tender_detail = _get_cancel_receipt(
        order,
        int(tender_id),
        json.loads(data)
    )

    success_update_tenders = update_tenders(
        pos_id,
        order.get("orderId"),
        tender_id,
        json.dumps(new_tender_detail)
    )

    return success_update_tenders


def _get_cancel_receipt(
    order,          # type: eTree
    tender_id,      # type: int
    cancel_data,    # type: Dict
):
    # type: (...) -> List

    for original_tender in order.findall('TenderHistory/Tender'):
        current_tender_id = int(original_tender.get('tenderId'))
        if current_tender_id == tender_id:
            tender = {}
            tender_detail = json.loads(original_tender.get("tenderDetail", {}))
            tender_detail["receiptCancel"] = cancel_data
            tender['tenderdetail'] = json.dumps(tender_detail)
            tender['tenderid'] = current_tender_id
            return [tender]


def get_electronic_payment_component_name(
    pos_id,     # type: Any[Union[str, int]]
):
    # type: (...) -> Optional[str]

    return get_device_service(
        pos_id=pos_id,
        device_type="eft"
    )

