import base64

from logging import Logger
from xml.etree import cElementTree as eTree

from interactor.route.order.save.dto import (
    OrderSaveRequest,
    SaveOrderResponse,
)

from model.error_type import ExternalServicesErrorsType
from model.exception import ExternalServiceErrors
from report import CashPaymentReport
from services import PrinterService
from model.repository import PosRepositoryModel

from model.config import (
    Config,
    MapValidatePosId,
)
from validation_util import (
    check_if_business_day_is_opened,
    check_if_operator_is_logged,
    check_if_order_is_totaled,
    validate_pos_id,
    check_has_due_amount,
)


class OrderSaveInteractor(object):
    def __init__(
        self,
        logger,             # type: Logger
        config,             # type: Config
        pos_repository,     # type: PosRepositoryModel
        printer_service,    # type: PrinterService
    ):
        # type: (...) -> None

        self.logger = logger
        self.config = config
        self.pos_repository = pos_repository
        self.printer_service = printer_service

    def execute(
        self,
        request,     # type: OrderSaveRequest
    ):
        # type: (...) -> SaveOrderResponse

        model_validate = MapValidatePosId(
            pos_id=request.pos_id,
            system_api_key=request.system_api_key,
            secure_api_key_list=self.config.api_key_mapping,
        )

        pos_id = validate_pos_id(
            request=model_validate,
        )

        model = self.pos_repository.get_model(
            pos_id=pos_id,
        )

        check_if_business_day_is_opened(
            repository=self.pos_repository,
            model=model,
        )
        check_if_operator_is_logged(
            repository=self.pos_repository,
            model=model,
        )
        check_if_order_is_totaled(
            repository=self.pos_repository,
            model=model,
        )
        check_has_due_amount(
            model=model,
            pos_id=pos_id,
            repository=self.pos_repository,
        )

        try:
            self.pos_repository.do_stored_order(
                model=model,
                pos_id=pos_id,
            )
        except Exception as _:
            self.logger.exception("Error stored order")
            raise ExternalServiceErrors(ExternalServicesErrorsType.StoredOrderError)

        return self._print_receipt(
            pos_id=pos_id,
            model=model,
            request=request,
        )

    def _print_receipt(
        self,
        pos_id,     # type: int
        model,      # type: eTree
        request,    # type: OrderSaveRequest
    ):
        # type: (...) -> SaveOrderResponse

        cash_report = CashPaymentReport(
            pos_id=pos_id,
        )

        current_order = self.pos_repository.get_current_order(
            model=model,
        )

        report_data = cash_report.generate(
            model=model,
            current_order=current_order,
        )
        if request.print_coupon:
            self.printer_service.send_print_data(
                model=model,
                response=report_data,
            )
            report_data = None

        report_data = base64.b64encode(report_data) if report_data is not None else ""

        return SaveOrderResponse(
            coupon=report_data,
        )
