package com.braintree.commands.impl;

import static com.braintree.enums.BraintreeThreeDSecureFlow.AUTO;

import com.braintree.configuration.service.BrainTreeConfigService;
import com.braintreegateway.AuthenticationInsight;
import com.braintreegateway.PaymentMethodNonceRequest;
import java.util.List;

import com.braintree.command.result.BrainTreePaymentMethodNonceResult;
import com.braintree.util.GenericBuilder;
import java.util.Optional;
import org.apache.commons.collections4.CollectionUtils;

import com.braintree.commands.BrainTreeCreatePaymentMethodNonceCommand;
import com.braintreegateway.PaymentMethodNonce;
import com.braintreegateway.Result;
import com.braintreegateway.ValidationError;
import com.braintreegateway.ValidationErrors;
import org.apache.commons.lang.StringUtils;


public class DefaultBrainTreeCreatePaymentMethodNonceCommand
        extends AbstractCommand<String, BrainTreePaymentMethodNonceResult>
        implements BrainTreeCreatePaymentMethodNonceCommand {

    private BrainTreeConfigService configService;

    @Override
    public BrainTreePaymentMethodNonceResult perform(final String methodToken) {
        Result<PaymentMethodNonce> brainTreeReply;
        if (configService.getThreeDSecureFlow().equals(AUTO)) {
            brainTreeReply = getBraintreeGateway()
                    .paymentMethodNonce()
                    .create(new PaymentMethodNonceRequest()
                            .paymentMethodToken(methodToken)
                            .merchantAccountId(configService.getCurrencyMerchantAccountId())
                            .authenticationInsight(true));
        } else {
            brainTreeReply = getBraintreeGateway()
                    .paymentMethodNonce()
                    .create(methodToken);
        }

        validateErrors(methodToken, brainTreeReply);

        return GenericBuilder.of(BrainTreePaymentMethodNonceResult::new)
                .with(BrainTreePaymentMethodNonceResult::setNonce, brainTreeReply.getTarget().getNonce())
                .with(BrainTreePaymentMethodNonceResult::setBin, brainTreeReply.getTarget().getDetails().getBin())
                .with(BrainTreePaymentMethodNonceResult::setEnvironment,
                        Optional.ofNullable(brainTreeReply.getTarget())
                        .map(PaymentMethodNonce::getAuthenticationInsight)
                        .map(AuthenticationInsight::getRegulationEnvironment).orElse(StringUtils.EMPTY))
                .build();
    }

    private void validateErrors(String request, Result<PaymentMethodNonce> brainTreeReply) {
        final ValidationErrors errors = brainTreeReply.getErrors();
        if (errors != null) {
            final List<ValidationError> validationErrors = errors.getAllDeepValidationErrors();
            if (CollectionUtils.isNotEmpty(validationErrors)) {
                final ValidationError validationError = validationErrors.get(0);
                getLoggingHandler().getLogger().info(
                    String.format("BT payment method nonce for token(%s) is creating with error: %s %s", request,
                        validationError.getCode(),
                        validationError.getMessage()));
            }
        }
    }

    public void setConfigService(BrainTreeConfigService configService) {
        this.configService = configService;
    }
}
