package com.braintree.actions.order;

import com.braintree.constants.BraintreefulfilmentprocessConstants;
import de.hybris.platform.basecommerce.enums.FraudStatus;
import de.hybris.platform.core.enums.OrderStatus;
import de.hybris.platform.core.model.order.OrderModel;
import de.hybris.platform.fraud.FraudService;
import de.hybris.platform.fraud.impl.FraudServiceResponse;
import de.hybris.platform.fraud.model.FraudReportModel;
import de.hybris.platform.orderhistory.model.OrderHistoryEntryModel;
import de.hybris.platform.orderprocessing.model.OrderProcessModel;
import de.hybris.platform.servicelayer.util.ServicesUtil;
import de.hybris.platform.util.Config;
import org.apache.log4j.Logger;

public class BrainTreeFraudCheckOrderAction extends AbstractFraudCheckAction<OrderProcessModel> {

    private static final Logger LOG = Logger.getLogger(BrainTreeFraudCheckOrderAction.class);

    private FraudService fraudService;
    private String providerName;

    @Override
    public Transition executeAction(final OrderProcessModel process) {
        LOG.info("Process: " + process.getCode() + " in step " + getClass());
        ServicesUtil.validateParameterNotNull(process, "Process can not be null");
        ServicesUtil.validateParameterNotNull(process.getOrder(), "Order can not be null");

        final double scoreLimit = getScoreLimit();
        final double scoreTolerance = getScoreTolerance();
        final String currentProviderName = getProviderName();

        final OrderModel order = process.getOrder();
        final FraudServiceResponse response = fraudService.recognizeOrderSymptoms(currentProviderName, order);
        final double score = response.getScore();
        if (score < scoreLimit) {
            final FraudReportModel fraudReport = createFraudReport(currentProviderName, response, order, FraudStatus.OK);
            final OrderHistoryEntryModel historyEntry = createHistoryLog(currentProviderName, order, FraudStatus.OK, null);
            order.setFraudulent(Boolean.FALSE);
            order.setPotentiallyFraudulent(Boolean.FALSE);
            order.setStatus(OrderStatus.FRAUD_CHECKED);
            modelService.save(fraudReport);
            modelService.save(historyEntry);
            modelService.save(order);
            return Transition.OK;
        } else if (score < scoreLimit + scoreTolerance) {
            final FraudReportModel fraudReport = createFraudReport(currentProviderName, response, order, FraudStatus.CHECK);
            final OrderHistoryEntryModel historyEntry = createHistoryLog(currentProviderName, order, FraudStatus.CHECK,
                    fraudReport.getCode());
            order.setFraudulent(Boolean.FALSE);
            order.setPotentiallyFraudulent(Boolean.TRUE);
            order.setStatus(OrderStatus.FRAUD_CHECKED);
            modelService.save(fraudReport);
            modelService.save(historyEntry);
            modelService.save(order);
            return Transition.POTENTIAL;
        } else {
            final FraudReportModel fraudReport = createFraudReport(currentProviderName, response, order, FraudStatus.FRAUD);
            final OrderHistoryEntryModel historyEntry = createHistoryLog(currentProviderName, order, FraudStatus.FRAUD,
                    fraudReport.getCode());
            order.setFraudulent(Boolean.TRUE);
            order.setPotentiallyFraudulent(Boolean.FALSE);
            order.setStatus(OrderStatus.FRAUD_CHECKED);
            modelService.save(fraudReport);
            modelService.save(historyEntry);
            modelService.save(order);
            return Transition.FRAUD;
        }
    }

    protected double getScoreTolerance() {
        return Double.parseDouble(
                Config.getParameter(BraintreefulfilmentprocessConstants.EXTENSIONNAME + ".fraud.scoreToleranceExternal"));
    }

    protected double getScoreLimit() {
        return Double.parseDouble(
                Config.getParameter(BraintreefulfilmentprocessConstants.EXTENSIONNAME + ".fraud.scoreLimitExternal"));
    }

    public void setFraudService(final FraudService fraudService) {
        this.fraudService = fraudService;
    }

    public void setProviderName(final String providerName) {
        this.providerName = providerName;
    }

    protected String getProviderName() {
        return providerName;
    }

}
