import json

from application.model import DefaultBenefitApplierRepository, BenefitAppliers, OperationDescription, OperationStatus
from application.model.configuration import Configurations
from application.repository.pos import DBRepository
from application.repository.pos.utils import find_benefit_applier
from typing import Dict


class ApplyBenefitInteractor(object):

    def __init__(self, configs, db_repository, benefit_appliers_repositories):
        # type: (Configurations, DBRepository, Dict[BenefitAppliers: DefaultBenefitApplierRepository]) -> None

        self.configs = configs
        self.logger = self.configs.logger
        self.db_repository = db_repository
        self.benefit_appliers_repositories = benefit_appliers_repositories

    def apply_benefit(
            self,
            current_pos_id,             # type: int
            originator_pos_id,          # type: int
            voucher_id,                 # type: str
            user_auth_level             # type: bool
    ):
        # type: (...) -> None

        benefit_applier = find_benefit_applier(originator_pos_id, voucher_id)

        message = "Trying to get and lock benefit to voucherId: {}; Current/Originator PosId: {}/{}; BenefitApplier: {}"
        self.logger.info(message.format(voucher_id, current_pos_id, originator_pos_id, benefit_applier))

        benefit = self.benefit_appliers_repositories[benefit_applier].get_benefit_and_lock(voucher_id)
        benefit_id = str(benefit.get("id"))

        try:
            self.logger.info("Benefit successfully obtained. BenefitId: {}".format(benefit_id))
            tender_id = self.configs.benefit_applier_tender_ids[benefit_applier]
            self.benefit_appliers_repositories[benefit_applier].add_benefit(
                    current_pos_id=current_pos_id,
                    benefit_id=benefit_id,
                    benefit=benefit,
                    benefit_applier=benefit_applier,
                    tender_id=tender_id,
                    user_auth_level=user_auth_level
            )

            self.db_repository.insert_or_update_pending_operation(
                benefit_id,
                current_pos_id,
                OperationDescription.APPLIED,
                OperationStatus.DONE,
                benefit_applier,
                0
            )
        except Exception as _:
            self.logger.exception("Error applying benefit. Trying to unlock. BenefitId: {}".format(benefit_id))
            self.benefit_appliers_repositories[benefit_applier].unlock_benefit(benefit_id)
            raise
