from abc import ABCMeta, abstractmethod
from logging import Logger

from cfgtools import Group
from dialogmanager import DialogManager
from mbcontextmessagehandler import MbContextMessageBus
from messagebus import (
    Event,
)

from modelcommon.model import SitefResponse

from typing import (
    Any,
    Union, Optional
)

from model import (
    CancelPaymentOrderData,
    ConfirmFinishPaymentData,
    FinishPaymentData,
    PaymentResponse,
    StartPaymentData,
    TestConnectionData,
)
from util import Cache


class PaymentProcessor(object):
    __metaclass__ = ABCMeta

    def __init__(
        self,
        message_bus,        # type: MbContextMessageBus
        dialog_manager,     # type: DialogManager
        config,             # type: Group
        logger,             # type: Logger
        cache,              # type: Optional[Cache]
    ):
        # type: (...) -> None

        self.message_bus = message_bus
        self.dialog_manager = dialog_manager
        self.config = config
        self.logger = logger
        self.cache = cache

    @abstractmethod
    def connection_status(self, test_connection_data):
        # type: (TestConnectionData) -> bool
        raise NotImplementedError()

    @abstractmethod
    def add_payment(self, start_payment_data):
        # type: (StartPaymentData) -> PaymentResponse
        raise NotImplementedError()

    @abstractmethod
    def cancel_payment_order(
        self,
        cancel_payment_order_data,  # type: CancelPaymentOrderData
        additional_params="",       # type: Optional[str]
    ):
        # type: (...) -> Any[Union[SitefResponse, str]]

        raise NotImplementedError()

    @abstractmethod
    def cancel_payment(self):
        # type: () -> str
        raise NotImplementedError()

    @abstractmethod
    def finish_payment(
        self,
        finish_payment_data     # type: FinishPaymentData
    ):
        # type: (...) -> bool
        raise NotImplementedError()

    @abstractmethod
    def confirm_finish_payment(
        self,
        confirm_finish_payment_data     # type: ConfirmFinishPaymentData
    ):
        # type: (...) -> None
        raise NotImplementedError()

    @abstractmethod
    def get_name(self):
        # type: () -> str
        raise NotImplementedError()

    @abstractmethod
    def get_document(
        self,
        pos_id      # type: str
    ):
        # type: (...) -> str

        raise NotImplementedError()

    def stop(self):
        # type: () -> None
        pass

    def get_qr_code_config(self):
        # type: () -> None
        pass

    @abstractmethod
    def get_last_receipt(
        self,
        eft_processor,      # type: Optional[str]
    ):
        # type: (...) -> str

        raise NotImplementedError()

    def register_eft_processor(
        self,
        pos_id,             # type: int
        processor_name      # type: str
    ):
        # type: (...) -> None

        event_data = str(processor_name)
        event_subject = "POS{}".format(pos_id)
        self.logger.debug("register_eft_processor: {}".format(event_data))

        event_xml = """<Event subject="{0}" type="{1}"><{2}>{3}</{2}></Event>"""
        event_xml = event_xml.format(event_subject, "REGISTER_EFT_PROCESSOR", "REGISTER_EFT_PROCESSOR", event_data)

        self.message_bus.publish_event(
            Event(
                subject=event_subject,
                event_type="REGISTER_EFT_PROCESSOR",
                data=event_xml,
            )
        )
