package com.braintree.populators;

import com.braintree.command.result.BrainTreeBillingAddressResult;
import com.braintree.command.result.BrainTreePaymentDetailsResult;
import com.braintree.constants.BraintreeConstants;
import com.braintree.hybris.data.graphql.commands.response.BrainTreeAddress;
import com.braintree.hybris.data.graphql.commands.response.BraintreePaymentMethodData;
import com.braintree.hybris.data.graphql.commands.response.BrainTreePaymentMethodDetails;
import com.braintree.hybris.data.graphql.commands.response.BrainTreePaymentMethodOrigin;
import com.braintree.payment.info.service.BraintreePaymentInfoService;
import de.hybris.platform.converters.Populator;
import de.hybris.platform.servicelayer.dto.converter.ConversionException;
import de.hybris.platform.servicelayer.dto.converter.Converter;
import org.apache.commons.lang.StringUtils;

import java.util.Optional;

import static com.braintree.constants.BraintreeConstants.US_BANK_ACCOUNT_DETAIL;

/**
 * Populates BrainTreePaymentDetailsResult from BrainTreePaymentMethod.
 */
public class BrainTreeGraphQLPaymentMethodToPaymentDetailsPopulator implements
        Populator<BraintreePaymentMethodData, BrainTreePaymentDetailsResult> {

    private BraintreePaymentInfoService braintreePaymentInfoService;
    private Converter<BrainTreeAddress, BrainTreeBillingAddressResult> graphQLAddressToAddressResult;

    @Override
    public void populate(BraintreePaymentMethodData source, BrainTreePaymentDetailsResult target)
            throws ConversionException {
        if (source != null) {
            target.setPaymentMethodToken(source.getLegacyId());
            target.setPaymentMethodGraphQLToken(source.getId());
            final BrainTreePaymentMethodDetails details = source.getDetails();
            if (details != null) {
                target.setEmail(details.getEmail());
                target.setCardType(Optional.ofNullable(details.getBrandCode()).orElse(StringUtils.EMPTY));
                target.setExpirationMonth(Optional.ofNullable(details.getExpirationMonth()).orElse(StringUtils.EMPTY));
                target.setExpirationYear(Optional.ofNullable(details.getExpirationYear()).orElse(StringUtils.EMPTY));
                target.setLast4(details.getLast4());
                if (!details.get__typename().equalsIgnoreCase(US_BANK_ACCOUNT_DETAIL) && details.getLast4() != null) {
                    target.setCardNumber(String.format(BraintreeConstants.CARD_NUMBER_MASK, details.getLast4()));
                } else {
                    target.setCardNumber(StringUtils.EMPTY);
                }
                target.setCardholderName(Optional.ofNullable(details.getCardholderName()).orElse(StringUtils.EMPTY));
                final BrainTreePaymentMethodOrigin origin = details.getOrigin();

                String originType = null;
                if (origin != null) {
                    originType = origin.getType();
                }
                if (details.getRoutingNumber() != null) {
                    target.setRoutingNumber(details.getRoutingNumber());
                }
                target.setVerified(details.isVerified());
                final String paymentProvider = braintreePaymentInfoService
                        .getPaymentProviderByDetailsAndOrigin(details.get__typename(), originType);
                target.setPaymentProvider(paymentProvider);
                target.setImageUrl(braintreePaymentInfoService
                        .getImageSourceByPaymentProviderAndCardType(paymentProvider, details.getBrandCode()));
                target.setBillingAddress(graphQLAddressToAddressResult.convert(source.getDetails().getBillingAddress()));
            }
        }
    }

    public void setBraintreePaymentInfoService(
            BraintreePaymentInfoService braintreePaymentInfoService) {
        this.braintreePaymentInfoService = braintreePaymentInfoService;
    }

    public void setGraphQLAddressToAddressResult(
            Converter<BrainTreeAddress, BrainTreeBillingAddressResult> graphQLAddressToAddressResult) {
        this.graphQLAddressToAddressResult = graphQLAddressToAddressResult;
    }
}
