from posot import OrderTaker

from model.error_type import OperationErrorsType
from model.exception import OperationErrors
from model.services import ElectronicPaymentServiceModel
from model.tokens import BusTokens
from typing import (
    Optional,
    List,
)
from xml.etree import cElementTree as eTree

from sysactions import get_used_service
from logging import Logger

from mbcontextmessagehandler import MbContextMessageBus
from messagebus import (
    Message,
)
from msgbus import (
    TK_SYS_ACK,
)


class ElectronicPaymentService(ElectronicPaymentServiceModel):
    def __init__(
        self,
        logger,                     # type: Logger
        message_bus,                # type: MbContextMessageBus
        electronic_payments_id,     # type: Optional[List[int]]
    ):
        # type: (...) -> None

        self.logger = logger
        self.message_bus = message_bus
        self.electronic_payments_id = electronic_payments_id

    def finish_transaction(
        self,
        model,                  # type: eTree
        pos_ot,                 # type: OrderTaker
        electronic_type_id,     # type: int
        pos_id,                 # type: str
        status,                 # type: str
        order_id="",            # type: Optional[str]
    ):
        # type: (...) -> Optional[Message]

        if electronic_type_id not in self.electronic_payments_id:
            return

        order_id = "" if order_id is None else order_id
        order = pos_ot.orderPicture(
            posid=pos_id,
            orderid=order_id,
        )

        if order is None:
            return

        order = eTree.XML(order).find("Order")
        created_at = order.get("createdAt").replace("-", "").replace(":", "")
        fiscal_date = created_at[:8]
        fiscal_time = created_at[9:15]
        order_id = order.get("orderId") if order_id == "" else order_id

        data = ";".join([str(pos_id), order_id, fiscal_date, fiscal_time, status, "", ""])

        payment_service = self.get_electronic_payment_service(model=model)

        for try_num in range(1, 4):
            try:

                msg = "[finish_eft_transactions] Trying to send a finish message. Order #: {}; Try #: {}; STATUS #: {}"
                self.logger.info(msg.format(order_id, try_num, status))

                message = Message(
                    token=BusTokens.TK_ELECTRONIC_PAYMENT_FINISH_PAYMENT,
                    timeout=600000000,
                    data=data,
                )
                response = self.message_bus.send_message(
                    component=payment_service,
                    message=message,
                )

                if response.token == TK_SYS_ACK:
                    msg = "[finish_eft_transactions] Success finished eft transaction. Order #: {}"
                    self.logger.info(msg.format(order_id))
                    return response

                message = "[finish_eft_transactions] ACK not received. Order #: {} - {} - {}"
                self.logger.info(message.format(order_id, response.token, response.data))

            except Exception as _:
                msg = "[finish_eft_transactions] Error sending message. Order #: {} / Try #: {} / Status: {}"
                msg = msg.format(order_id, try_num, status)
                if try_num == 3:
                    self.logger.exception(msg, exc_info=True)
                else:
                    self.logger.info(msg)

        return None

    @staticmethod
    def get_electronic_payment_service(
        model,      # type: eTree
    ):
        # type: (...) -> str

        payment_service = get_used_service(
            model=model,
            service_type="eft",
        )

        if payment_service:
            return payment_service
        raise OperationErrors(OperationErrorsType.InvalidPaymentService)

