package com.braintree.populators;

import com.braintree.enums.BrainTreeCardType;
import com.braintree.enums.BrainTreePaymentMethod;
import com.braintree.model.BrainTreePaymentInfoModel;
import com.braintreegateway.Address;
import com.braintreegateway.AmexExpressCheckoutCard;
import com.braintreegateway.AndroidPayCard;
import com.braintreegateway.ApplePayCard;
import com.braintreegateway.CreditCard;
import com.braintreegateway.PayPalAccount;
import com.braintreegateway.PaymentMethod;
import com.braintreegateway.VisaCheckoutCard;
import de.hybris.platform.converters.Populator;
import de.hybris.platform.core.model.user.AddressModel;
import de.hybris.platform.servicelayer.dto.converter.ConversionException;
import de.hybris.platform.servicelayer.dto.converter.Converter;

import java.util.Calendar;
import java.util.Date;

public class BraintreePaymentMethodPopulator implements Populator<PaymentMethod, BrainTreePaymentInfoModel> {

    private Converter<Address, AddressModel> braintreeAddressConverter;

    @Override
    public void populate(PaymentMethod method, BrainTreePaymentInfoModel model) throws ConversionException {
        if (method != null && model != null) {
            model.setPaymentMethodToken(method.getToken());
            model.setImageSource(method.getImageUrl());
            model.setIsDefault(method.isDefault());

            if (method instanceof CreditCard) {
                saveCreditCardInfo((CreditCard) method, model);
            } else if (method instanceof PayPalAccount) {
                savePayPalInfo((PayPalAccount) method, model);
            } else if (method instanceof ApplePayCard) {
                saveApplePayCardInfo((ApplePayCard) method, model);
            } else if (method instanceof AndroidPayCard) {
                saveAndroidPayCardInfo((AndroidPayCard) method, model);
            } else if (method instanceof VisaCheckoutCard) {
                saveSrcCardInfo((VisaCheckoutCard) method, model);
            } else if (method instanceof AmexExpressCheckoutCard) {
                saveAmexExpressCheckoutCardInfo((AmexExpressCheckoutCard) method, model);
            }
        }
    }

    private void saveCreditCardInfo(final CreditCard method, final BrainTreePaymentInfoModel model) {
        final CreditCard cc = method;
        final String formattedCardNumber = String.format("%s******%s", cc.getBin(), cc.getLast4());
        model.setPaymentInfo(formattedCardNumber);
        model.setUpdatedAt(cc.getUpdatedAt().getTime());
        model.setCustomerId(cc.getCustomerId());
        model.setCardType(BrainTreeCardType.valueOf(cc.getCardType()));
        model.setCardholderName(cc.getCardholderName());
        model.setCardNumber(formattedCardNumber);
        model.setExpirationMonth(cc.getExpirationMonth());
        model.setExpirationYear(cc.getExpirationYear());
        model.setCustomerLocation(cc.getCustomerLocation());
        model.setCreatedAt(formatDate(cc.getCreatedAt()));
        model.setPaymentProvider(BrainTreePaymentMethod.CREDITCARD.toString());

        final Address billingAddress = cc.getBillingAddress();
        if (billingAddress != null) {
            model.setBillingAddress(getBraintreeAddressConverter().convert(billingAddress));
        }
    }

    private void savePayPalInfo(final PayPalAccount method, final BrainTreePaymentInfoModel model) {
        final PayPalAccount ppa = method;
        model.setPaymentInfo(ppa.getEmail());
        model.setUpdatedAt(ppa.getUpdatedAt().getTime());
        model.setCustomerId(ppa.getCustomerId());
        model.setCreatedAt(formatDate(ppa.getCreatedAt()));
        model.setPaymentProvider(BrainTreePaymentMethod.PAYPAL.toString());
    }

    private void saveApplePayCardInfo(final ApplePayCard method, final BrainTreePaymentInfoModel model) {
        final ApplePayCard apc = method;
        model.setPaymentInfo(String.format("%s******%s", apc.getBin(), apc.getLast4()));
        model.setUpdatedAt(apc.getUpdatedAt().getTime());
        model.setCreatedAt(formatDate(apc.getCreatedAt()));
        model.setExpirationMonth(apc.getExpirationMonth());
        model.setExpirationYear(apc.getExpirationYear());
        model.setPaymentProvider(BrainTreePaymentMethod.APPLEPAYCARD.toString());
    }

    private void saveAndroidPayCardInfo(final AndroidPayCard method, final BrainTreePaymentInfoModel model) {
        final AndroidPayCard apc = method;
        model.setPaymentInfo(String.format("%s******%s", apc.getBin(), apc.getLast4()));
        model.setUpdatedAt(apc.getUpdatedAt().getTime());
        model.setCreatedAt(formatDate(apc.getCreatedAt()));
        model.setExpirationMonth(apc.getExpirationMonth());
        model.setExpirationYear(apc.getExpirationYear());
        model.setPaymentProvider(BrainTreePaymentMethod.ANDROIDPAYCARD.toString());
    }

    private void saveSrcCardInfo(final VisaCheckoutCard method, final BrainTreePaymentInfoModel model) {
        model.setUpdatedAt(method.getUpdatedAt().getTime());
        model.setCreatedAt(formatDate(method.getCreatedAt()));
        model.setPaymentInfo(String.format("%s******%s", method.getBin(), method.getLast4()));
        model.setExpirationMonth(method.getExpirationMonth());
        model.setExpirationYear(method.getExpirationYear());
        model.setPaymentProvider(BrainTreePaymentMethod.VISACHECKOUTCARD.toString());
    }

    private void saveAmexExpressCheckoutCardInfo(final AmexExpressCheckoutCard method,
                                                 final BrainTreePaymentInfoModel model) {
        final AmexExpressCheckoutCard aecc = method;
        model.setPaymentInfo(aecc.getBin());
        model.setUpdatedAt(aecc.getUpdatedAt().getTime());
        model.setCreatedAt(formatDate(aecc.getCreatedAt()));
        model.setCustomerId(aecc.getCustomerId());
        model.setExpirationMonth(aecc.getExpirationMonth());
        model.setExpirationYear(aecc.getExpirationYear());
        model.setPaymentProvider(BrainTreePaymentMethod.AMEXEXPRESSCHECKOUTCARD.toString());
    }

    private static Date formatDate(final Calendar createdAt) {
        if (createdAt != null) {
            return createdAt.getTime();
        }
        return null;
    }

    public Converter<Address, AddressModel> getBraintreeAddressConverter() {
        return braintreeAddressConverter;
    }

    public void setBraintreeAddressConverter(final Converter<Address, AddressModel> braintreeAddressConverter) {
        this.braintreeAddressConverter = braintreeAddressConverter;
    }
}
