package bank.discovery.service.fv.is.credit.ws.api.v1;

import bank.discovery.service.fv.framework.client.FVClientConsent;
import bank.discovery.service.fv.framework.exception.FinancialVitalityException;
import bank.discovery.service.fv.framework.exception.HttpStatusException;
import bank.discovery.service.fv.framework.exception.StandardFinancialVitalityException;
import bank.discovery.service.fv.framework.logging.Log;
import bank.discovery.service.fv.framework.model.dto.common.SimpleMemberDto;
import bank.discovery.service.fv.framework.model.enums.ElementCategoryEnum;
import bank.discovery.service.fv.framework.model.enums.ElementSubCategoryEnum;
import bank.discovery.service.fv.framework.model.enums.ProductType;
import bank.discovery.service.fv.framework.model.enums.SecuredUnsecuredIndicator;
import bank.discovery.service.fv.framework.model.enums.VerifiedUnverifiedIndicator;
import bank.discovery.service.fv.framework.model.enums.exception.ProgramIDEnum;
import bank.discovery.service.fv.framework.model.enums.exception.StandardFinancialVitalityStatusEnum;
import bank.discovery.service.fv.framework.util.DateUtils;
import bank.discovery.service.fv.is.credit.ws.api.v1.async.QueryAssessmentFeedbackAsyncHandler;
import bank.discovery.service.fv.is.credit.ws.client.eas.CreditDebtBalanceClient;
import bank.discovery.service.fv.is.credit.ws.client.eas.CreditInformationClientHelper;
import bank.discovery.service.fv.is.credit.ws.client.fv.assessment.QueryAssessmentFeedbackClient;
import bank.discovery.service.fv.is.credit.ws.model.api.v1.CreditDebtBalanceResponseDetail;
import bank.discovery.service.fv.is.credit.ws.model.api.v1.CreditGetDebtBalanceRequest;
import bank.discovery.service.fv.is.credit.ws.model.api.v1.CreditGetDebtBalanceResponse;
import bank.discovery.service.fv.is.credit.ws.model.api.v1.CreditInformationRequest;
import bank.discovery.service.fv.is.credit.ws.model.api.v1.CreditInformationResponse;
import bank.discovery.service.fv.is.credit.ws.model.api.v1.CreditInformationResponseDetail;
import bank.discovery.service.fv.is.credit.ws.model.api.v1.QueryFeeRequest;
import bank.discovery.service.fv.is.credit.ws.model.api.v1.QueryFeeResponse;
import bank.discovery.service.fv.is.credit.ws.model.api.v1.QueryFeeResponseDetail;
import bank.discovery.service.fv.is.credit.ws.model.api.v1.QueryInterestRequest;
import bank.discovery.service.fv.is.credit.ws.model.api.v1.QueryInterestResponse;
import bank.discovery.service.fv.is.credit.ws.model.api.v1.QueryInterestResponseDetail;
import bank.discovery.service.fv.is.credit.ws.model.api.v1.QueryPenaltyFeeRequest;
import bank.discovery.service.fv.is.credit.ws.model.api.v1.QueryPenaltyFeeResponse;
import bank.discovery.service.fv.is.credit.ws.model.api.v1.QueryPenaltyFeeResponseDetail;
import bank.discovery.service.fv.is.credit.ws.model.api.v1.QueryRepaymentRequest;
import bank.discovery.service.fv.is.credit.ws.model.api.v1.QueryRepaymentResponse;
import bank.discovery.service.fv.is.credit.ws.model.api.v1.QueryRepaymentResponseDetail;
import bank.discovery.service.fv.is.credit.ws.model.client.fv.assessment.QueryAssessmentFeedbackRepeatedElements;
import bank.discovery.service.fv.is.credit.ws.model.client.fv.assessment.QueryAssessmentFeedbackRequest;
import bank.discovery.service.fv.is.credit.ws.model.client.fv.assessment.QueryAssessmentFeedbackResponse;
import bank.discovery.service.fv.is.credit.ws.model.client.fv.assessment.QueryAssessmentFeedbackResponseDetail;
import bank.discovery.service.fv.is.credit.ws.model.client.fv.assessment.QueryAssessmentMultiPartFeedback;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.helpers.NOPLogger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

/**
 * It will have business logic and will also call methods on CreditDebtBalanceClient class.
 * <p/>
 * Created by yogesh12 on 2017/07/19.
 */
@Component("helper.api.v1.credit")
public class CreditRestControllerHelper {

    @Log
    private final Logger LOGGER = NOPLogger.NOP_LOGGER;

    private final CreditDebtBalanceClient creditDebtBalanceClient;
    private final FVClientConsent consentClient;
    private final CreditInformationClientHelper creditInformationClientHelper;
    private final QueryAssessmentFeedbackClient queryAssessmentFeedbackClient;

    @Autowired
    public CreditRestControllerHelper(
            @Qualifier("helper.client.eas.creditInformation") CreditInformationClientHelper creditInformationClientHelper,
            @Qualifier("client.eas.creditDebtBalance") CreditDebtBalanceClient creditDebtBalanceClient,
            @Qualifier("remote.sap.ws.consent.fv.FVClientConsent") FVClientConsent consentClient,
            @Qualifier("client.fv.assessment.queryAssessmentFeedbackClient") QueryAssessmentFeedbackClient queryAssessmentFeedbackClient) {
        this.creditDebtBalanceClient = creditDebtBalanceClient;
        this.consentClient = consentClient;
        this.creditInformationClientHelper = creditInformationClientHelper;
        this.queryAssessmentFeedbackClient = queryAssessmentFeedbackClient;
    }

    /**
     * This method will pass the call from controller to service layer to get required data and
     * will also implement business logic.
     *
     * @param creditGetDebtBalanceRequest an object of CreditGetDebtBalanceRequest type.
     * @return creditGetDebtBalanceResponse an object of CreditGetDebtBalanceResponse type.
     */
    public CreditGetDebtBalanceResponse queryDebtBalance(CreditGetDebtBalanceRequest creditGetDebtBalanceRequest)
            throws StandardFinancialVitalityException {
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("queryDebtBalance() method of CreditRestControllerHelper class is invoked.");
        }

        if (creditGetDebtBalanceRequest == null) {
            if (LOGGER.isWarnEnabled()) {
                LOGGER.warn("Request object is null. Throwing exception as NULL_INPUT_VALUE_NOT_ALLOWED.");
            }

            throw new StandardFinancialVitalityException(StandardFinancialVitalityStatusEnum.NULL_INPUT_VALUE_NOT_ALLOWED,
                    new String[]{"GetDebtBalanceRequest"});
        } else {
            if (!CollectionUtils.isEmpty(creditGetDebtBalanceRequest.getMemberList())) {
                for (SimpleMemberDto simpleMemberDto : creditGetDebtBalanceRequest.getMemberList()
                        ) {
                    if (StringUtils.isBlank(simpleMemberDto.getClientId())) {
                        throw new StandardFinancialVitalityException(StandardFinancialVitalityStatusEnum.NULL_INPUT_VALUE_NOT_ALLOWED,
                                new String[]{"ClientId"});
                    }
                    if (StringUtils.isBlank(simpleMemberDto.getProgramId())) {
                        throw new StandardFinancialVitalityException(StandardFinancialVitalityStatusEnum.NULL_INPUT_VALUE_NOT_ALLOWED,
                                new String[]{"ProgramID"});
                    }
                }
            }
            if (creditGetDebtBalanceRequest.getFreshnessPeriod() == null) {
                creditGetDebtBalanceRequest.setFreshnessPeriod(0);
            }
        }

        CreditGetDebtBalanceResponse creditGetDebtBalanceResponse = new CreditGetDebtBalanceResponse();

        if (consentClient.queryClientConsent().isClientConsent()) {
            if (LOGGER.isInfoEnabled()) {
                LOGGER.info("Client has given consent to query 3rd party");
            }
            for (SimpleMemberDto simpleMemberDto : creditGetDebtBalanceRequest.getMemberList()) {
                List<CreditDebtBalanceResponseDetail> creditDebtBalanceResponseDetailList = creditDebtBalanceClient
                        .queryDebtBalance(simpleMemberDto.getClientId());
                creditGetDebtBalanceResponse.getDetails().addAll(creditDebtBalanceResponseDetailList);
            }
        } else {
            if (LOGGER.isInfoEnabled()) {
                LOGGER.info("Client has not given consent to query 3rd party, hence returning empty response");
            }
        }
        return creditGetDebtBalanceResponse;
    }


    /**
     * This method makes a call to the service to get the creditDebtBalanceClient information and then
     * sets the creditDebtBalanceClient information that needs to be returned.
     *
     * @param creditInformationRequest input parameters for queryCreditInformation {@link CreditInformationRequest}
     * @return a custom response object {@link CreditInformationResponse}
     * @throws FinancialVitalityException thrown if one of the input parameters are either null or empty
     */
    public CreditInformationResponse queryCreditInformation(CreditInformationRequest creditInformationRequest)
            throws StandardFinancialVitalityException, HttpStatusException {
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("queryCreditInformation() method of CreditRestControllerHelper class is invoked.");
        }

        if (creditInformationRequest == null) {
            if (LOGGER.isWarnEnabled()) {
                LOGGER.warn("Request object is null. Throwing exception as NULL_INPUT_VALUE_NOT_ALLOWED.");
            }

            throw new StandardFinancialVitalityException(StandardFinancialVitalityStatusEnum.NULL_INPUT_VALUE_NOT_ALLOWED,
                    new String[]{"creditInformationRequest"});
        } else {
            if (creditInformationRequest.getMemberList() == null || creditInformationRequest.getMemberList().isEmpty()) {
                if (LOGGER.isWarnEnabled()) {
                    LOGGER.warn("SimpleMemberList in request object is null or empty. Throwing exception as NULL_INPUT_VALUE_NOT_ALLOWED.");
                }

                throw new StandardFinancialVitalityException(StandardFinancialVitalityStatusEnum.NULL_INPUT_VALUE_NOT_ALLOWED,
                        new String[]{"memberList"});
            }
            if (creditInformationRequest.getFreshnessPeriod() == null) {
                creditInformationRequest.setFreshnessPeriod(0);
            }
        }
        List<CompletableFuture<CreditInformationResponseDetail>> creditInformationResponseDetail = new ArrayList<>();

        String clientId;
        ProductType productType = null;

        if (creditInformationRequest.getProductType() != null) {
            productType = creditInformationRequest.getProductType();
        }

        SecuredUnsecuredIndicator secUnsecIndicator = creditInformationRequest.getSecUnsecIndicator();
        Integer freshnessPeriod = creditInformationRequest.getFreshnessPeriod();

        for (SimpleMemberDto simpleMemberDto : creditInformationRequest.getMemberList()) {
            clientId = simpleMemberDto.getClientId();
            CompletableFuture<CreditInformationResponseDetail> creditDebtBalanceResponseDetailList = creditInformationClientHelper
                    .queryCreditInformation(clientId, secUnsecIndicator, freshnessPeriod, productType);

            if (creditDebtBalanceResponseDetailList == null) {
                continue;
            }
            creditInformationResponseDetail.add(creditDebtBalanceResponseDetailList);
        }

        CompletableFuture.allOf(creditInformationResponseDetail.toArray(new CompletableFuture[creditInformationResponseDetail.size()])).join();

        CreditInformationResponse creditInformationResponse = new CreditInformationResponse();
        try {
            for (CompletableFuture<CreditInformationResponseDetail> entity : creditInformationResponseDetail) {
                creditInformationResponse.getDetails().add(entity.get());
            }
        } catch (InterruptedException | ExecutionException e) {
            LOGGER.error("Async operation related exception occurred. Throwing exception as UNHANDLED_RUNTIME_EXCEPTION.", e);
            throw new StandardFinancialVitalityException(StandardFinancialVitalityStatusEnum.UNHANDLED_RUNTIME_EXCEPTION,
                    new String[]{e.getClass().getSimpleName()});
        }
        return creditInformationResponse;
    }

    /**
     * The ‘Query Penalty Fee For Credit’ service is used to retrieve Penalty Fee Information for accounts held by a client
     *
     * @param queryPenaltyRequest input parameters for queryPenaltyFee {@link QueryPenaltyFeeRequest}
     * @return a custom response object {@link QueryPenaltyFeeResponse}
     * @throws FinancialVitalityException thrown if one of the input parameters are either null or empty
     */
    public QueryPenaltyFeeResponse queryPenaltyFee(QueryPenaltyFeeRequest queryPenaltyRequest)
            throws StandardFinancialVitalityException, HttpStatusException {

        if (queryPenaltyRequest == null) {
            throw new StandardFinancialVitalityException(StandardFinancialVitalityStatusEnum.NULL_INPUT_VALUE_NOT_ALLOWED,
                    new String[]{"queryPenaltyRequest"});
        } else {
            if (!CollectionUtils.isEmpty(queryPenaltyRequest.getMemberList())) {
                for (SimpleMemberDto simpleMemberDto : queryPenaltyRequest.getMemberList()
                        ) {
                    if (StringUtils.isBlank(simpleMemberDto.getClientId())) {
                        throw new StandardFinancialVitalityException(StandardFinancialVitalityStatusEnum.NULL_INPUT_VALUE_NOT_ALLOWED,
                                new String[]{"ClientId"});
                    }

                    String programID = null;
                    try {
                        programID = ProgramIDEnum.valueOf(simpleMemberDto.getProgramId()).toString();
                    } catch (IllegalArgumentException e) {
                        throw new StandardFinancialVitalityException(StandardFinancialVitalityStatusEnum.INVALID_INPUT_PARAMETER,
                                new Object[]{"Program Id", programID});
                    }

                    if (StringUtils.isBlank(programID)) {
                        throw new StandardFinancialVitalityException(StandardFinancialVitalityStatusEnum.NULL_INPUT_VALUE_NOT_ALLOWED,
                                new String[]{"ProgramID"});
                    }
                }
            } else {
                throw new StandardFinancialVitalityException(StandardFinancialVitalityStatusEnum.NULL_INPUT_VALUE_NOT_ALLOWED, "membershipList");
            }
            if (queryPenaltyRequest.getFreshnessPeriod() == null) {
                queryPenaltyRequest.setFreshnessPeriod(0);
            }
        }

        QueryPenaltyFeeResponse queryPenaltyResponse = new QueryPenaltyFeeResponse();
        List<QueryPenaltyFeeResponseDetail> queryPenaltyResponseDetails = new ArrayList<>();
        QueryPenaltyFeeResponseDetail queryPenaltyResponseDetail;

        /**
         *  Below we are getting the answer for "Will you have to pay penalty fees if you settle any of your accounts early?"
         *  and we specifically getting the Penalty Fee Indicator
         */
        QueryAssessmentFeedbackRequest queryAssessmentFeedbackRequestPenaltyFeeIndicator = new QueryAssessmentFeedbackRequest();
        queryAssessmentFeedbackRequestPenaltyFeeIndicator.setMemberList(queryPenaltyRequest.getMemberList());
        queryAssessmentFeedbackRequestPenaltyFeeIndicator.setElementCategoryCode(ElementCategoryEnum.UNSECDEBT.getElementCategoryCode());
        queryAssessmentFeedbackRequestPenaltyFeeIndicator.setElementSubCategoryCode(ElementSubCategoryEnum.PENLTY_IND.getElementSubCategoryCode());
        queryAssessmentFeedbackRequestPenaltyFeeIndicator.setEffectiveFrom(DateUtils.BOT_DATE);
        queryAssessmentFeedbackRequestPenaltyFeeIndicator.setEffectiveTo(DateUtils.EOT_DATE);

        QueryAssessmentFeedbackResponse queryAssessmentFeedbackResponsePenaltyFeeIndicator = queryAssessmentFeedbackClient
                .call(queryAssessmentFeedbackRequestPenaltyFeeIndicator);

        /**
         *  Below we are getting the answer for "Will you have to pay penalty fees if you settle any of your accounts early?"
         *  and we specifically getting the Penalty Fee Amount
         */
        QueryAssessmentFeedbackRequest queryAssessmentFeedbackRequestPenaltyFeeAmount = new QueryAssessmentFeedbackRequest();
        queryAssessmentFeedbackRequestPenaltyFeeAmount.setMemberList(queryPenaltyRequest.getMemberList());
        queryAssessmentFeedbackRequestPenaltyFeeAmount.setElementCategoryCode(ElementCategoryEnum.UNSECDEBT.getElementCategoryCode());
        queryAssessmentFeedbackRequestPenaltyFeeAmount.setElementSubCategoryCode(ElementSubCategoryEnum.PENLTY_AMT.getElementSubCategoryCode());
        queryAssessmentFeedbackRequestPenaltyFeeAmount.setEffectiveFrom(DateUtils.BOT_DATE);
        queryAssessmentFeedbackRequestPenaltyFeeAmount.setEffectiveTo(DateUtils.EOT_DATE);

        QueryAssessmentFeedbackResponse queryAssessmentFeedbackResponsePenaltyFeeAmount = queryAssessmentFeedbackClient
                .call(queryAssessmentFeedbackRequestPenaltyFeeAmount);

        for (SimpleMemberDto simpleMemberDto : queryPenaltyRequest.getMemberList()) {

            if ((queryAssessmentFeedbackResponsePenaltyFeeIndicator != null && !CollectionUtils
                    .isEmpty(queryAssessmentFeedbackResponsePenaltyFeeIndicator.getFeedback())) && (
                    queryAssessmentFeedbackResponsePenaltyFeeAmount != null
                            && !CollectionUtils.isEmpty(queryAssessmentFeedbackResponsePenaltyFeeAmount.getFeedback()))) {

                for (QueryAssessmentFeedbackResponseDetail queryAssessmentFeedbackResponseDetailPenaltyFeeInd : queryAssessmentFeedbackResponsePenaltyFeeIndicator
                        .getFeedback()) {

                    if (queryAssessmentFeedbackResponseDetailPenaltyFeeInd.getFeedbackString() != null) {

                        for (QueryAssessmentFeedbackResponseDetail queryAssessmentFeedbackResponseDetailFeeAmount : queryAssessmentFeedbackResponsePenaltyFeeAmount
                                .getFeedback()) {

                            if ((simpleMemberDto.getClientId().equals(queryAssessmentFeedbackResponseDetailFeeAmount.getMembershipRoleID()))
                                    && (simpleMemberDto.getClientId()
                                    .equals(queryAssessmentFeedbackResponseDetailPenaltyFeeInd.getMembershipRoleID()))) {

                                if (queryAssessmentFeedbackResponseDetailFeeAmount.getFeedbackString() != null) {

                                    for (QueryAssessmentFeedbackRepeatedElements repeatedElementsPenaltyFeeInd : queryAssessmentFeedbackResponseDetailPenaltyFeeInd
                                            .getRepeatedElements()) {

                                        for (QueryAssessmentFeedbackRepeatedElements repeatedElementPenaltyFeeAmount : queryAssessmentFeedbackResponseDetailFeeAmount
                                                .getRepeatedElements()) {

                                            if (repeatedElementPenaltyFeeAmount.getElementString()
                                                    .equals(repeatedElementsPenaltyFeeInd.getElementString())) {

                                                for (QueryAssessmentMultiPartFeedback assessmentMultiPartFeedBackPenaltyFeeInd : repeatedElementsPenaltyFeeInd
                                                        .getMultipartFeedback()) {

                                                    for (QueryAssessmentMultiPartFeedback assessmentMultiPartFeedBackPenaltyFeeAmount : repeatedElementPenaltyFeeAmount
                                                            .getMultipartFeedback()) {

                                                        queryPenaltyResponseDetail = new QueryPenaltyFeeResponseDetail();

                                                        queryPenaltyResponseDetail.setCreditor(repeatedElementPenaltyFeeAmount.getElementString());
                                                        queryPenaltyResponseDetail.setPenaltyFeeApplicationIndicator(
                                                                assessmentMultiPartFeedBackPenaltyFeeInd.getFeedbackString());
                                                        queryPenaltyResponseDetail.setPenaltyFee(
                                                                new BigDecimal(assessmentMultiPartFeedBackPenaltyFeeAmount.getFeedbackString()));

                                                        queryPenaltyResponseDetails.add(queryPenaltyResponseDetail);

                                                    }
                                                }
                                            }

                                        }
                                    }
                                } else {

                                    for (QueryAssessmentFeedbackRepeatedElements repeatedElementsPenaltyFeeInd : queryAssessmentFeedbackResponseDetailPenaltyFeeInd
                                            .getRepeatedElements()) {

                                        for (QueryAssessmentMultiPartFeedback assessmentMultiPartFeedBackPenaltyFeeInd : repeatedElementsPenaltyFeeInd
                                                .getMultipartFeedback()) {

                                            queryPenaltyResponseDetail = new QueryPenaltyFeeResponseDetail();

                                            queryPenaltyResponseDetail.setCreditor(repeatedElementsPenaltyFeeInd.getElementString());
                                            queryPenaltyResponseDetail.setPenaltyFeeApplicationIndicator(
                                                    assessmentMultiPartFeedBackPenaltyFeeInd.getFeedbackString());
                                            queryPenaltyResponseDetail.setPenaltyFee(null);

                                            queryPenaltyResponseDetails.add(queryPenaltyResponseDetail);
                                        }

                                    }

                                }
                            }
                        }
                    }
                }
            }
        }

        queryPenaltyResponse.setDetails(queryPenaltyResponseDetails);

        return queryPenaltyResponse;
    }


    /**
     * The ‘Query Fee For Credit’ service is used to retrieve Fee Information for accounts held by a client.
     *
     * @param queryFeeRequest input parameters for queryFee {@link QueryFeeRequest}
     * @return a custom response object {@link QueryFeeResponse}
     * @throws FinancialVitalityException thrown if one of the input parameters are either null or empty
     */
    public QueryFeeResponse queryFee(QueryFeeRequest queryFeeRequest) throws StandardFinancialVitalityException, HttpStatusException {

        if (queryFeeRequest == null) {
            throw new StandardFinancialVitalityException(StandardFinancialVitalityStatusEnum.NULL_INPUT_VALUE_NOT_ALLOWED,
                    new String[]{"queryFeeRequest"});
        } else {
            if (!CollectionUtils.isEmpty(queryFeeRequest.getMemberList())) {
                for (SimpleMemberDto simpleMemberDto : queryFeeRequest.getMemberList()
                        ) {
                    if (StringUtils.isBlank(simpleMemberDto.getClientId())) {
                        throw new StandardFinancialVitalityException(StandardFinancialVitalityStatusEnum.NULL_INPUT_VALUE_NOT_ALLOWED,
                                new String[]{"ClientId"});
                    }

                    String programID = null;
                    try {
                        programID = ProgramIDEnum.valueOf(simpleMemberDto.getProgramId()).toString();
                    } catch (IllegalArgumentException e) {
                        throw new StandardFinancialVitalityException(StandardFinancialVitalityStatusEnum.INVALID_INPUT_PARAMETER,
                                new Object[]{"Program Id", programID});
                    }

                    if (StringUtils.isBlank(programID)) {
                        throw new StandardFinancialVitalityException(StandardFinancialVitalityStatusEnum.NULL_INPUT_VALUE_NOT_ALLOWED,
                                new String[]{"ProgramID"});
                    }
                }
            } else {
                throw new StandardFinancialVitalityException(StandardFinancialVitalityStatusEnum.NULL_INPUT_VALUE_NOT_ALLOWED, "membershipList");
            }
            if (queryFeeRequest.getFreshnessPeriod() == null) {
                queryFeeRequest.setFreshnessPeriod(0);
            }
        }

        QueryFeeResponse queryFeeResponse = new QueryFeeResponse();
        List<QueryFeeResponseDetail> queryFeeResponseDetails = new ArrayList<>();
        QueryFeeResponseDetail queryFeeResponseDetail;

        /**
         *  Below we are getting the answer for "What is the monthly fee that you pay for each of the accounts listed below?"
         *  and we specifically getting the Monthly Account Fee Indicator
         */
        QueryAssessmentFeedbackRequest queryAssessmentFeedbackRequestFixedAmountOrPercentage = new QueryAssessmentFeedbackRequest();
        queryAssessmentFeedbackRequestFixedAmountOrPercentage.setMemberList(queryFeeRequest.getMemberList());
        queryAssessmentFeedbackRequestFixedAmountOrPercentage.setElementCategoryCode(ElementCategoryEnum.UNSECDEBT.getElementCategoryCode());
        queryAssessmentFeedbackRequestFixedAmountOrPercentage.setElementSubCategoryCode(ElementSubCategoryEnum.FEE_IND.getElementSubCategoryCode());
        queryAssessmentFeedbackRequestFixedAmountOrPercentage.setEffectiveFrom(DateUtils.BOT_DATE);
        queryAssessmentFeedbackRequestFixedAmountOrPercentage.setEffectiveTo(DateUtils.EOT_DATE);

        QueryAssessmentFeedbackResponse queryAssessmentFeedbackResponseFixedAmountOrPercentage = queryAssessmentFeedbackClient
                .call(queryAssessmentFeedbackRequestFixedAmountOrPercentage);

        /**
         *  Below we are getting the answer for "What is the monthly fee that you pay for each of the accounts listed below?"
         *  and we specifically getting the Monthly Account Fee Amount
         */
        QueryAssessmentFeedbackRequest queryAssessmentFeedbackRequestFeeAmount = new QueryAssessmentFeedbackRequest();
        queryAssessmentFeedbackRequestFeeAmount.setMemberList(queryFeeRequest.getMemberList());
        queryAssessmentFeedbackRequestFeeAmount.setElementCategoryCode(ElementCategoryEnum.UNSECDEBT.getElementCategoryCode());
        queryAssessmentFeedbackRequestFeeAmount.setElementSubCategoryCode(ElementSubCategoryEnum.FEE_AMT.getElementSubCategoryCode());
        queryAssessmentFeedbackRequestFeeAmount.setEffectiveFrom(DateUtils.BOT_DATE);
        queryAssessmentFeedbackRequestFeeAmount.setEffectiveTo(DateUtils.EOT_DATE);

        QueryAssessmentFeedbackResponse queryAssessmentFeedbackResponseFeeAmount = queryAssessmentFeedbackClient
                .call(queryAssessmentFeedbackRequestFeeAmount);

        for (SimpleMemberDto simpleMemberDto : queryFeeRequest.getMemberList()) {

            if ((queryAssessmentFeedbackResponseFixedAmountOrPercentage != null && !CollectionUtils
                    .isEmpty(queryAssessmentFeedbackResponseFixedAmountOrPercentage.getFeedback())) && (
                    queryAssessmentFeedbackResponseFeeAmount != null
                            && !CollectionUtils.isEmpty(queryAssessmentFeedbackResponseFeeAmount.getFeedback()))) {

                for (QueryAssessmentFeedbackResponseDetail queryAssessmentFeedbackResponseDetailFixedAmtOrPercentage : queryAssessmentFeedbackResponseFixedAmountOrPercentage
                        .getFeedback()) {

                    if (queryAssessmentFeedbackResponseDetailFixedAmtOrPercentage.getFeedbackString() != null) {

                        for (QueryAssessmentFeedbackResponseDetail queryAssessmentFeedbackResponseDetailForFeeAmount : queryAssessmentFeedbackResponseFeeAmount
                                .getFeedback()) {

                            if ((simpleMemberDto.getClientId().equals(queryAssessmentFeedbackResponseDetailForFeeAmount.getMembershipRoleID()))
                                    && (simpleMemberDto.getClientId()
                                    .equals(queryAssessmentFeedbackResponseDetailFixedAmtOrPercentage.getMembershipRoleID()))) {

                                if (queryAssessmentFeedbackResponseDetailForFeeAmount.getFeedbackString() != null) {

                                    for (QueryAssessmentFeedbackRepeatedElements repeatedElementsFixedAmtOrPercentage : queryAssessmentFeedbackResponseDetailFixedAmtOrPercentage
                                            .getRepeatedElements()) {

                                        for (QueryAssessmentFeedbackRepeatedElements repeatedElementFeeAmount : queryAssessmentFeedbackResponseDetailForFeeAmount
                                                .getRepeatedElements()) {

                                            if (repeatedElementFeeAmount.getElementString()
                                                    .equals(repeatedElementsFixedAmtOrPercentage.getElementString())) {

                                                for (QueryAssessmentMultiPartFeedback assessmentMultiPartFeedBackForFixedAmtOrPercentage : repeatedElementsFixedAmtOrPercentage
                                                        .getMultipartFeedback()) {

                                                    for (QueryAssessmentMultiPartFeedback assessmentMultiPartFeedBackForFeeAmount : repeatedElementFeeAmount
                                                            .getMultipartFeedback()) {

                                                        queryFeeResponseDetail = new QueryFeeResponseDetail();
                                                        queryFeeResponseDetail.setCreditor(repeatedElementFeeAmount.getElementString());
                                                        queryFeeResponseDetail.setPercentageAmountIndicator(
                                                                assessmentMultiPartFeedBackForFixedAmtOrPercentage.getFeedbackString());
                                                        queryFeeResponseDetail.setFee(
                                                                new BigDecimal(assessmentMultiPartFeedBackForFeeAmount.getFeedbackString()));

                                                        queryFeeResponseDetails.add(queryFeeResponseDetail);

                                                    }
                                                }
                                            }

                                        }
                                    }
                                } else {

                                    for (QueryAssessmentFeedbackRepeatedElements repeatedElementsFixedAmtOrPercentage : queryAssessmentFeedbackResponseDetailFixedAmtOrPercentage
                                            .getRepeatedElements()) {

                                        for (QueryAssessmentMultiPartFeedback assessmentMultiPartFeedBackForFixedAmtOrPercentage : repeatedElementsFixedAmtOrPercentage
                                                .getMultipartFeedback()) {

                                            queryFeeResponseDetail = new QueryFeeResponseDetail();

                                            queryFeeResponseDetail.setCreditor(repeatedElementsFixedAmtOrPercentage.getElementString());
                                            queryFeeResponseDetail.setPercentageAmountIndicator(
                                                    assessmentMultiPartFeedBackForFixedAmtOrPercentage.getFeedbackString());
                                            queryFeeResponseDetail.setFee(null);

                                            queryFeeResponseDetails.add(queryFeeResponseDetail);
                                        }

                                    }

                                }
                            }
                        }
                    }
                }
            }
        }

        queryFeeResponse.setDetails(queryFeeResponseDetails);

        return queryFeeResponse;
    }


    /**
     * The ‘Query Interest For Credit’ service is used to extract Interest Information for accounts held by a client.
     *
     * @param queryInterestRequest input parameters for queryInterest {@link QueryInterestRequest}
     * @return a custom response object {@link QueryInterestResponse}
     * @throws FinancialVitalityException thrown if one of the input parameters are either null or empty
     */
    public QueryInterestResponse queryInterest(QueryInterestRequest queryInterestRequest)
            throws StandardFinancialVitalityException, HttpStatusException {

        if (queryInterestRequest == null) {
            throw new StandardFinancialVitalityException(StandardFinancialVitalityStatusEnum.NULL_INPUT_VALUE_NOT_ALLOWED,
                    new String[]{"queryFeeRequest"});
        } else {
            if (!CollectionUtils.isEmpty(queryInterestRequest.getMemberList())) {
                for (SimpleMemberDto simpleMemberDto : queryInterestRequest.getMemberList()
                        ) {
                    if (StringUtils.isBlank(simpleMemberDto.getClientId())) {
                        throw new StandardFinancialVitalityException(StandardFinancialVitalityStatusEnum.NULL_INPUT_VALUE_NOT_ALLOWED,
                                new String[]{"ClientId"});
                    }
                    String programID = null;
                    try {
                        programID = ProgramIDEnum.valueOf(simpleMemberDto.getProgramId()).toString();
                    } catch (IllegalArgumentException e) {
                        throw new StandardFinancialVitalityException(StandardFinancialVitalityStatusEnum.INVALID_INPUT_PARAMETER,
                                new Object[]{"Program Id", programID});
                    }

                    if (StringUtils.isBlank(programID)) {
                        throw new StandardFinancialVitalityException(StandardFinancialVitalityStatusEnum.NULL_INPUT_VALUE_NOT_ALLOWED,
                                new String[]{"ProgramID"});
                    }
                }
            } else {
                throw new StandardFinancialVitalityException(StandardFinancialVitalityStatusEnum.NULL_INPUT_VALUE_NOT_ALLOWED, "membershipList");
            }
            if (queryInterestRequest.getFreshnessPeriod() == null) {
                queryInterestRequest.setFreshnessPeriod(0);
            }
        }

        QueryInterestResponse queryInterestResponse = new QueryInterestResponse();
        List<QueryInterestResponseDetail> queryInterestResponseDetails = new ArrayList<>();
        QueryInterestResponseDetail queryInterestResponseDetail;

        /**
         *  Below we are getting the answer for "Are you paying interest on the accounts listed below?"
         *  and we specifically getting the Interest Paid Indicator
         *
         */
        QueryAssessmentFeedbackRequest queryAssessmentFeedbackRequestInterestRate = new QueryAssessmentFeedbackRequest();
        queryAssessmentFeedbackRequestInterestRate.setMemberList(queryInterestRequest.getMemberList());
        queryAssessmentFeedbackRequestInterestRate.setElementCategoryCode(ElementCategoryEnum.UNSECDEBT.getElementCategoryCode());
        queryAssessmentFeedbackRequestInterestRate.setElementSubCategoryCode(ElementSubCategoryEnum.INT_RATE.getElementSubCategoryCode());
        queryAssessmentFeedbackRequestInterestRate.setEffectiveFrom(DateUtils.BOT_DATE);
        queryAssessmentFeedbackRequestInterestRate.setEffectiveTo(DateUtils.EOT_DATE);

        QueryAssessmentFeedbackResponse queryAssessmentFeedbackResponseInterestRate = queryAssessmentFeedbackClient
                .call(queryAssessmentFeedbackRequestInterestRate);

        /**
         *  Below we are getting the answer for "What is the interest rate on the accounts listed below?"
         *  and we specifically getting the Account Interest Rate Value
         *
         */
        QueryAssessmentFeedbackRequest queryAssessmentFeedbackRequestInterestPaid = new QueryAssessmentFeedbackRequest();
        queryAssessmentFeedbackRequestInterestPaid.setMemberList(queryInterestRequest.getMemberList());
        queryAssessmentFeedbackRequestInterestPaid.setElementCategoryCode(ElementCategoryEnum.UNSECDEBT.getElementCategoryCode());
        queryAssessmentFeedbackRequestInterestPaid.setElementSubCategoryCode(ElementSubCategoryEnum.INT_PAID.getElementSubCategoryCode());
        queryAssessmentFeedbackRequestInterestPaid.setEffectiveFrom(DateUtils.BOT_DATE);
        queryAssessmentFeedbackRequestInterestPaid.setEffectiveTo(DateUtils.EOT_DATE);

        QueryAssessmentFeedbackResponse queryAssessmentFeedbackResponseInterestPaid = queryAssessmentFeedbackClient
                .call(queryAssessmentFeedbackRequestInterestPaid);

        for (SimpleMemberDto simpleMemberDto : queryInterestRequest.getMemberList()) {

            if ((queryAssessmentFeedbackResponseInterestRate != null && !CollectionUtils
                    .isEmpty(queryAssessmentFeedbackResponseInterestRate.getFeedback())) && (queryAssessmentFeedbackResponseInterestPaid != null
                    && !CollectionUtils.isEmpty(queryAssessmentFeedbackResponseInterestPaid.getFeedback()))) {

                for (QueryAssessmentFeedbackResponseDetail queryAssessmentFeedbackResponseDetailForInterestRate : queryAssessmentFeedbackResponseInterestRate
                        .getFeedback()) {

                    if (queryAssessmentFeedbackResponseDetailForInterestRate.getFeedbackString() != null) {

                        for (QueryAssessmentFeedbackResponseDetail queryAssessmentFeedbackResponseDetailForInterestPaid : queryAssessmentFeedbackResponseInterestPaid
                                .getFeedback()) {

                            if ((simpleMemberDto.getClientId().equals(queryAssessmentFeedbackResponseDetailForInterestPaid.getMembershipRoleID()))
                                    && (simpleMemberDto.getClientId()
                                    .equals(queryAssessmentFeedbackResponseDetailForInterestRate.getMembershipRoleID()))) {

                                if (queryAssessmentFeedbackResponseDetailForInterestPaid.getFeedbackString() != null) {

                                    for (QueryAssessmentFeedbackRepeatedElements repeatedElementsInterestRate : queryAssessmentFeedbackResponseDetailForInterestRate
                                            .getRepeatedElements()) {

                                        for (QueryAssessmentFeedbackRepeatedElements repeatedElementInterestPaid : queryAssessmentFeedbackResponseDetailForInterestPaid
                                                .getRepeatedElements()) {

                                            if (repeatedElementInterestPaid.getElementString()
                                                    .equals(repeatedElementsInterestRate.getElementString())) {

                                                for (QueryAssessmentMultiPartFeedback assessmentMultiPartFeedBackForInterestRate : repeatedElementsInterestRate
                                                        .getMultipartFeedback()) {

                                                    for (QueryAssessmentMultiPartFeedback assessmentMultiPartFeedBackForInterestPaid : repeatedElementInterestPaid
                                                            .getMultipartFeedback()) {

                                                        queryInterestResponseDetail = new QueryInterestResponseDetail();

                                                        queryInterestResponseDetail.setCreditor(repeatedElementInterestPaid.getElementString());
                                                        queryInterestResponseDetail.setInterestApplicableIndicator(
                                                                assessmentMultiPartFeedBackForInterestRate.getFeedbackString());
                                                        queryInterestResponseDetail.setInterest(
                                                                new BigDecimal(assessmentMultiPartFeedBackForInterestPaid.getFeedbackString()));

                                                        queryInterestResponseDetails.add(queryInterestResponseDetail);

                                                    }
                                                }
                                            }

                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        queryInterestResponse.setDetails(queryInterestResponseDetails);

        return queryInterestResponse;

    }

    /**
     * Inner class to manage the extraction of data
     */
    private class ResponseTransformationBridge{

        private String fixedOrPercentage;
        private String minPayAmount;
        private String minPayPeriod;
        private String repaymentTermIndicator;
        private String repaymentTermValue;

        private String getFixedOrPercentage() {
            return fixedOrPercentage;
        }

        private void setFixedOrPercentage(String fixedOrPercentage) {
            this.fixedOrPercentage = fixedOrPercentage;
        }

        private String getMinPayAmount() {
            return minPayAmount;
        }

        private void setMinPayAmount(String minPayAmount) {
            this.minPayAmount = minPayAmount;
        }

        private String getMinPayPeriod() {
            return minPayPeriod;
        }

        private void setMinPayPeriod(String minPayPeriod) {
            this.minPayPeriod = minPayPeriod;
        }

        private String getRepaymentTermIndicator() {
            return repaymentTermIndicator;
        }

        private void setRepaymentTermIndicator(String repaymentTermIndicator) {
            this.repaymentTermIndicator = repaymentTermIndicator;
        }

        private String getRepaymentTermValue() {
            return repaymentTermValue;
        }

        private void setRepaymentTermValue(String repaymentTermValue) {
            this.repaymentTermValue = repaymentTermValue;
        }
    }

    /**
     * The ‘Query Repayment For Credit’ service is used to retrieve Repayment Information for accounts held by a client.
     *
     * @param queryRepaymentRequest input parameters for queryRepayment {@link QueryRepaymentRequest}
     * @return a custom response object {@link QueryRepaymentResponse}
     * @throws FinancialVitalityException thrown if one of the input parameters are either null or empty
     */
    public QueryRepaymentResponse queryRepayment(QueryRepaymentRequest queryRepaymentRequest) throws FinancialVitalityException {

        QueryRepaymentResponse queryRepaymentResponse = new QueryRepaymentResponse();
        List<QueryRepaymentResponseDetail> queryRepaymentResponseDetails = new ArrayList<>();

        ExecutorService executor = null;

        List<Future<HashMap<String, HashMap<String, QueryAssessmentFeedbackResponseDetail>>>> futureList = new ArrayList<>();
        List<Callable<HashMap<String, HashMap<String, QueryAssessmentFeedbackResponseDetail>>>> callableList = new ArrayList<>();

        HashMap<String, ResponseTransformationBridge> transformedResponse = null;

        try {

            executor = Executors.newFixedThreadPool(6);

            QueryAssessmentFeedbackAsyncHandler externalInfoQueryHandler = new QueryAssessmentFeedbackAsyncHandler(queryAssessmentFeedbackClient);

            callableList.add(() -> externalInfoQueryHandler.execute(queryRepaymentRequest.getMemberList(), ElementCategoryEnum.UNSECDEBT,
                                                                    ElementSubCategoryEnum.MINPAY_IND, DateUtils.BOT_DATE, DateUtils.EOT_DATE,
                                                                    VerifiedUnverifiedIndicator.UNVERIFIED));

            callableList.add(() -> externalInfoQueryHandler.execute(queryRepaymentRequest.getMemberList(), ElementCategoryEnum.UNSECDEBT,
                                                                    ElementSubCategoryEnum.MINPAY_AMT, DateUtils.BOT_DATE, DateUtils.EOT_DATE,
                                                                    VerifiedUnverifiedIndicator.UNVERIFIED));

            callableList.add(() -> externalInfoQueryHandler.execute(queryRepaymentRequest.getMemberList(), ElementCategoryEnum.UNSECDEBT,
                                                                    ElementSubCategoryEnum.MINPAY_PER, DateUtils.BOT_DATE, DateUtils.EOT_DATE,
                                                                    VerifiedUnverifiedIndicator.UNVERIFIED));

            callableList.add(() -> externalInfoQueryHandler.execute(queryRepaymentRequest.getMemberList(), ElementCategoryEnum.UNSECDEBT,
                                                                    ElementSubCategoryEnum.TERM_IND, DateUtils.BOT_DATE, DateUtils.EOT_DATE,
                                                                    VerifiedUnverifiedIndicator.UNVERIFIED));

            callableList.add(() -> externalInfoQueryHandler.execute(queryRepaymentRequest.getMemberList(), ElementCategoryEnum.UNSECDEBT,
                                                                    ElementSubCategoryEnum.TERM_VAL, DateUtils.BOT_DATE, DateUtils.EOT_DATE,
                                                                    VerifiedUnverifiedIndicator.UNVERIFIED));

            futureList = executor.invokeAll(callableList, 10000, TimeUnit.MILLISECONDS);
            executor.shutdown();

            List<HashMap<String, HashMap<String, QueryAssessmentFeedbackResponseDetail>>> feedbackResponses = new ArrayList<>();

            for (Future future : futureList) {
                if (future.get() != null && !(future.get() instanceof Exception)) {
                    feedbackResponses.add((HashMap<String, HashMap<String, QueryAssessmentFeedbackResponseDetail>>) future.get());
                }
            }
            transformedResponse = transformFutureListResponse(queryRepaymentRequest.getMemberList(),feedbackResponses);

        } catch (InterruptedException iEx) {
            LOGGER.error("Interrupted exception occurred", iEx);
        } catch (CancellationException cEx) {
            LOGGER.error("Cancellation exception occurred", cEx);
        } catch (ExecutionException exEx) {
            LOGGER.error("Execution exception occurred",  exEx);
        } finally {
            if (executor != null && !executor.isShutdown()) {
                executor.shutdown();
            }
        }
        QueryRepaymentResponseDetail queryRepaymentResponseDetail = null;
        ResponseTransformationBridge responseTransformationBridge;

        if (transformedResponse != null) {
            for (String key : transformedResponse.keySet()) {

                responseTransformationBridge = transformedResponse.get(key);

                queryRepaymentResponseDetail = new QueryRepaymentResponseDetail();
                queryRepaymentResponseDetail.setCreditor(key);

                queryRepaymentResponseDetail.setAmountPercentageIndicator(responseTransformationBridge.getFixedOrPercentage());

                if (responseTransformationBridge.getMinPayAmount() != null && !responseTransformationBridge.getMinPayAmount().isEmpty()) {
                    queryRepaymentResponseDetail.setRepayment(new BigDecimal(responseTransformationBridge.getMinPayAmount()));
                }

                queryRepaymentResponseDetail.setFixedRepaymentTermIndicator(responseTransformationBridge.getRepaymentTermIndicator());

                if (responseTransformationBridge.getRepaymentTermValue() != null && !responseTransformationBridge.getRepaymentTermValue().isEmpty()) {
                    queryRepaymentResponseDetail.setTerm(new Integer(responseTransformationBridge.getRepaymentTermValue()));
                }
                queryRepaymentResponseDetails.add(queryRepaymentResponseDetail);
            }
        }
        queryRepaymentResponse.setDetails(queryRepaymentResponseDetails);
        return queryRepaymentResponse;
    }

    /**
     * This method transforms the future response into a usable format response
     * @param simpleMemberDtoList
     * @param feedbackResponses
     * @return
     */
    private HashMap<String, ResponseTransformationBridge> transformFutureListResponse(List<SimpleMemberDto> simpleMemberDtoList, List<HashMap<String, HashMap<String, QueryAssessmentFeedbackResponseDetail>>> feedbackResponses) {

        HashMap<String, ResponseTransformationBridge> transformedResponse = new HashMap<>();

        for (SimpleMemberDto simpleMemberDto : simpleMemberDtoList) {

            for (HashMap<String, HashMap<String, QueryAssessmentFeedbackResponseDetail>> assessmentFeedbackWithSubCategory : feedbackResponses) {

                if (assessmentFeedbackWithSubCategory.containsKey(ElementSubCategoryEnum.MINPAY_IND.getElementSubCategoryCode())) {
                    transformData(assessmentFeedbackWithSubCategory,ElementSubCategoryEnum.MINPAY_IND, simpleMemberDto, transformedResponse);
                    continue;
                }

                if (assessmentFeedbackWithSubCategory.containsKey(ElementSubCategoryEnum.MINPAY_AMT.getElementSubCategoryCode() )) {
                    transformData(assessmentFeedbackWithSubCategory,ElementSubCategoryEnum.MINPAY_AMT, simpleMemberDto, transformedResponse);
                    continue;
                }

                if (assessmentFeedbackWithSubCategory.containsKey(ElementSubCategoryEnum.MINPAY_PER.getElementSubCategoryCode())) {
                    transformData(assessmentFeedbackWithSubCategory,ElementSubCategoryEnum.MINPAY_PER, simpleMemberDto, transformedResponse);
                    continue;
                }

                if (assessmentFeedbackWithSubCategory.containsKey(ElementSubCategoryEnum.TERM_IND.getElementSubCategoryCode())) {
                    transformData(assessmentFeedbackWithSubCategory,ElementSubCategoryEnum.TERM_IND, simpleMemberDto, transformedResponse);
                    continue;
                }

                if (assessmentFeedbackWithSubCategory.containsKey(ElementSubCategoryEnum.TERM_VAL.getElementSubCategoryCode())) {
                    transformData(assessmentFeedbackWithSubCategory,ElementSubCategoryEnum.TERM_VAL, simpleMemberDto, transformedResponse);
                }
            }
        }
        return transformedResponse;
    }

    /**
     * This function extracts data and assigns it to a map in order to be transformed into a final response
     * @param assessmentFeedbackWithSubCategory
     * @param elementSubCategoryEnum
     * @param simpleMemberDto
     * @param transformedResponse
     */
    private void transformData(HashMap<String, HashMap<String, QueryAssessmentFeedbackResponseDetail>> assessmentFeedbackWithSubCategory,
                               ElementSubCategoryEnum elementSubCategoryEnum, SimpleMemberDto simpleMemberDto,
                               HashMap<String, ResponseTransformationBridge> transformedResponse) {

        QueryAssessmentFeedbackResponseDetail queryAssessmentFeedbackResponseDetail = assessmentFeedbackWithSubCategory.get(elementSubCategoryEnum.getElementSubCategoryCode()).get(simpleMemberDto.getClientId());

        if (queryAssessmentFeedbackResponseDetail != null) {
            for (QueryAssessmentFeedbackRepeatedElements assessmentFeedbackRepeatedElements : queryAssessmentFeedbackResponseDetail.getRepeatedElements()) {

                if (!transformedResponse.containsKey(assessmentFeedbackRepeatedElements.getElementString())) {
                    transformedResponse.put(assessmentFeedbackRepeatedElements.getElementString(), new ResponseTransformationBridge());
                }

                if (elementSubCategoryEnum == ElementSubCategoryEnum.MINPAY_IND) {
                    transformedResponse.get(assessmentFeedbackRepeatedElements.getElementString()).setFixedOrPercentage(assessmentFeedbackRepeatedElements.getMultipartFeedback() != null &&
                                                                                                                        !assessmentFeedbackRepeatedElements.getMultipartFeedback().isEmpty() ?
                                                                                                                        assessmentFeedbackRepeatedElements.getMultipartFeedback().get(0).getFeedbackString() : null);
                } else if (elementSubCategoryEnum == ElementSubCategoryEnum.MINPAY_AMT) {
                    transformedResponse.get(assessmentFeedbackRepeatedElements.getElementString()).setMinPayAmount(assessmentFeedbackRepeatedElements.getMultipartFeedback() != null &&
                                                                                                                        !assessmentFeedbackRepeatedElements.getMultipartFeedback().isEmpty() ?
                                                                                                                        assessmentFeedbackRepeatedElements.getMultipartFeedback().get(0).getFeedbackString() : null);
                } else if (elementSubCategoryEnum == ElementSubCategoryEnum.MINPAY_PER) {
                    transformedResponse.get(assessmentFeedbackRepeatedElements.getElementString()).setMinPayPeriod(assessmentFeedbackRepeatedElements.getMultipartFeedback() != null &&
                                                                                                                        !assessmentFeedbackRepeatedElements.getMultipartFeedback().isEmpty() ?
                                                                                                                        assessmentFeedbackRepeatedElements.getMultipartFeedback().get(0).getFeedbackString() : null);

                } else if (elementSubCategoryEnum == ElementSubCategoryEnum.TERM_IND) {
                    transformedResponse.get(assessmentFeedbackRepeatedElements.getElementString()).setRepaymentTermIndicator(assessmentFeedbackRepeatedElements.getMultipartFeedback() != null &&
                                                                                                                        !assessmentFeedbackRepeatedElements.getMultipartFeedback().isEmpty() ?
                                                                                                                        assessmentFeedbackRepeatedElements.getMultipartFeedback().get(0).getFeedbackString() : null);
                } else if (elementSubCategoryEnum == ElementSubCategoryEnum.TERM_VAL) {
                    transformedResponse.get(assessmentFeedbackRepeatedElements.getElementString()).setRepaymentTermValue(assessmentFeedbackRepeatedElements.getMultipartFeedback() != null &&
                                                                                                                        !assessmentFeedbackRepeatedElements.getMultipartFeedback().isEmpty() ?
                                                                                                                        assessmentFeedbackRepeatedElements.getMultipartFeedback().get(0).getFeedbackString() : null);
                }
            }
        }
    }


}