from helper import remove_accents
from pos_model import Order, XmlTenderTypeFromPOSMapper, TenderType, OrderTender

from _SatXmlPartBuilder import SatXmlPartBuilder
from models import CfeTender
from satbuilder import ContextKeys
from typing import Dict


class PgtoBuilder(SatXmlPartBuilder):
    def __init__(
        self,               # type: PgtoBuilder
        tenders_type,       # type: Dict
        layout_version,     # type: str
    ):
        # type: (...) -> None

        self.tenders_type = tenders_type

        self.cfe_tender = CfeTender(layout_version=layout_version)
        self.tenders = self._get_tenders()

    def _get_tenders(
        self,       # type: PgtoBuilder
    ):
        # type: (...) -> Dict[int, Dict]

        tenders = {}
        for tender in self.tenders_type.values():
            tenders[int(tender["tenderId"])] = tender

        return tenders

    def build_xml(
        self,           # type: PgtoBuilder
        order,          # type: Order
        context,        # type: ContextKeys
    ):
        # type: (...) -> unicode

        xml = "<pgto>"
        max_order_tenders = 10

        if len(order.tenders) <= max_order_tenders:
            for tender in order.tenders:
                tender_type = XmlTenderTypeFromPOSMapper.get(tender.type)
                if tender.type in self.tenders:
                    t_pag = self.tenders[tender.type].get("tPag")
                    if t_pag is not None:
                        tender_type = int(self.tenders[tender.type].get("tPag"))

                cad_mc = self._get_cad_mc(tender)
                xml += self._get_mp_tag(
                    tender_type=tender_type,
                    tender_amount=tender.amount,
                    cad_mc=cad_mc,
                )
        else:
            tenders_amount = {}
            for tender in order.tenders:
                cad_mc = self._get_cad_mc(tender)
                if cad_mc not in tenders_amount:
                    tenders_amount[cad_mc] = {}

                tender_type = XmlTenderTypeFromPOSMapper.get(tender.type)
                if tender_type not in tenders_amount[cad_mc]:
                    tenders_amount[cad_mc][tender_type] = 0

                tenders_amount[cad_mc][tender_type] += tender.amount

            payment_groups = 0
            for cad_mc, tenders in tenders_amount.items():
                for tender_type in tenders:
                    amount = tenders[tender_type]
                    xml += self._get_mp_tag(
                        tender_type=tender_type,
                        tender_amount=amount,
                        cad_mc=cad_mc,
                    )
                    payment_groups += 1

            if payment_groups > max_order_tenders:
                message = "$ORDER_NOT_FINALIZED_DUE_TO_MAX_SAT_PAYMENT_GROUPS_REACHED|{}"
                raise Exception(message.format(max_order_tenders))

        xml += "</pgto>"

        return xml

    def _get_mp_tag(
        self,               # type: PgtoBuilder
        tender_type,        # type: int
        tender_amount,      # type: float
        cad_mc,             # type: str
    ):
        # type: (...) -> str

        tag = "<MP><cMP>{0:>02}</cMP><vMP>{1:>0.2f}</vMP><cAdmC>{2}</cAdmC></MP>"
        cmp_tag = self.cfe_tender.get_tpag(tender_type)
        return tag.format(cmp_tag, tender_amount, cad_mc)

    def _get_cad_mc(
            self,
            tender  # type: OrderTender
    ):
        # type: (...) -> str

        if tender.type in [TenderType.credit, TenderType.debit] and tender.accreditor_sat not in ['', None]:
            return str(tender.accreditor_sat)

        others = "999"
        tender_description = str(remove_accents(tender.descr)).upper()
        if tender_description in self.tenders_type:
            tender_type_data_base = self.tenders_type[tender_description]
            cad_mc = str(tender_type_data_base.get("cAdmC", ""))
            return cad_mc if cad_mc.strip() else others

        return others
