from logging import Logger
from typing import Any

from model.error_type import ExternalServicesErrorsType
from interactor.route.payment.insert.dto import (
    OrderInsertPaymentRequest,
    OrderInsertPaymentResponse
)
from model.config import Config
from model.exception import ExternalServiceErrors
from model.repository import PosRepositoryModel
from validation_util import \
    check_if_business_day_is_opened, \
    check_if_operator_is_logged, \
    check_if_order_is_totaled, \
    check_if_payment_type_is_valid, \
    check_if_payment_amount_is_valid, \
    validate_api_key


class OrderInsertPaymentInteractor(object):
    def __init__(self, logger, config, pos_repository, fiscal_service):
        # type: (Logger, Config, PosRepositoryModel, Any) -> None

        self.logger = logger
        self.config = config
        self.pos_repository = pos_repository
        self.fiscal_service = fiscal_service

    def execute(self, request):
        # type: (OrderInsertPaymentRequest) -> OrderInsertPaymentResponse

        pos_id = validate_api_key(request, self.config.api_key_mapping)
        model = self.pos_repository.get_model(pos_id)
        check_if_business_day_is_opened(self.pos_repository, model)
        check_if_operator_is_logged(self.pos_repository, model)
        check_if_order_is_totaled(self.pos_repository, model)
        check_if_payment_type_is_valid(self.config.allowed_payment_methods, request.payment_id)
        check_if_payment_amount_is_valid(request.amount, model)

        pos_ot = self.pos_repository.get_pos_ot(model)

        try:
            self.fiscal_service.process_payment(model, request)
        except Exception as _:
            self.logger.exception("Error performing payment")
            raise ExternalServiceErrors(ExternalServicesErrorsType.InsertPaymentUnavailable)

        tender = self.pos_repository.do_tender(pos_id, request.payment_id, pos_ot, request.amount)
        response = OrderInsertPaymentResponse(tender)

        return response
