package com.braintree.converters.utils;

import com.braintree.constants.BraintreeConstants;
import com.braintree.constants.BraintreeConstants.InstrumentType;
import com.braintree.hybris.data.BraintreeTransactionEntryCustomerData;
import com.braintree.hybris.data.BraintreeTransactionEntryDetailData;
import com.braintree.hybris.data.BraintreeTransactionEntryPayPalData;
import com.braintree.hybris.data.BraintreeTransactionEntryPaymentData;
import com.braintree.hybris.data.BraintreeTransactionOriginEntryData;
import com.braintree.hybris.data.graphql.commands.response.BrainTreeCustomer;
import com.braintree.hybris.data.graphql.commands.response.BrainTreePayPalAccountDetails;
import com.braintree.hybris.data.graphql.commands.response.BrainTreePaymentMethodSnapshot;
import com.braintree.hybris.data.graphql.commands.response.BrainTreePaymentStatusEvent;
import com.braintree.hybris.data.graphql.commands.response.BrainTreeTransaction;
import com.braintree.hybris.data.graphql.commands.response.BrainTreeTransactionAuthorizationProcessorResponse;
import com.braintreegateway.CreditCard;
import com.braintreegateway.Customer;
import com.braintreegateway.PayPalDetails;
import com.braintreegateway.Transaction;
import de.hybris.platform.jalo.JaloSession;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
import org.apache.commons.lang.StringUtils;


public class BraintreeTransactionConverterUtils {

    public static final String TRANSACTION_REFUND_SIGN = "yes";

    private BraintreeTransactionConverterUtils() {
        //empty to avoid instantiating this constant class
    }

    public static BraintreeTransactionEntryDetailData convertDetails(final Transaction transaction) {
        final BraintreeTransactionEntryDetailData data = new BraintreeTransactionEntryDetailData();
        data.setCustomerInfo(convertCustomerInfo(transaction));
        data.setPaymentInfo(convertPaymentInfo(transaction));
        data.setPaymentPayPalInfo(convertPaymentPayPalInfo(transaction));
        data.setTransactionInfo(convertOriginalTransactionInfo(transaction));
        return data;
    }

    public static BraintreeTransactionEntryDetailData convertDetails(final BrainTreeTransaction transaction) {
        final BraintreeTransactionEntryDetailData data = new BraintreeTransactionEntryDetailData();
        data.setCustomerInfo(convertCustomerInfo(transaction));
        data.setPaymentInfo(convertPaymentInfo(transaction));
        data.setPaymentPayPalInfo(convertPaymentPayPalInfo(transaction));
        data.setTransactionInfo(convertOriginalTransactionInfo(transaction));
        return data;
    }

    static BraintreeTransactionEntryCustomerData convertCustomerInfo(final Transaction transaction) {
        final BraintreeTransactionEntryCustomerData customerData = new BraintreeTransactionEntryCustomerData();
        final Customer customer = transaction.getCustomer();
        if (customer != null) {
            customerData.setCustomerID(customer.getId());
            customerData.setCustomerGraphQLID(customer.getGraphQLId());
            customerData.setName(formedName(customer.getFirstName(), customer.getLastName()));
            customerData.setEmail(customer.getEmail());
        }
        return customerData;
    }

    static BraintreeTransactionEntryCustomerData convertCustomerInfo(final BrainTreeTransaction transaction) {
        final BraintreeTransactionEntryCustomerData customerData = new BraintreeTransactionEntryCustomerData();
        final BrainTreeCustomer customer = transaction.getCustomer();
        if (customer != null) {
            customerData.setCustomerID(customer.getLegacyId());
            customerData.setCustomerGraphQLID(customer.getId());
            customerData.setName(formedName(customer.getFirstName(), customer.getLastName()));
            customerData.setEmail(customer.getEmail());
        }
        return customerData;
    }

    protected static BraintreeTransactionEntryPaymentData convertPaymentInfo(final Transaction transaction) {
        final BraintreeTransactionEntryPaymentData paymentData = new BraintreeTransactionEntryPaymentData();
        if (InstrumentType.CREDIT_CARD_PAYMENT_INSTRUMENT_TYPE.equals(transaction.getPaymentInstrumentType())) {
            final CreditCard creditCard = transaction.getCreditCard();
            if (creditCard != null) {
                paymentData.setCardholderName(creditCard.getCardholderName());
                paymentData.setCardType(creditCard.getCardType());
                paymentData
                    .setCreditCardNumber(String.format("%s******%s", creditCard.getBin(), creditCard.getLast4()));
                paymentData.setExpirationDate(creditCard.getExpirationDate());
                paymentData.setPaymentType(BraintreeConstants.CREDIT_CARD_PAYMENT_TYPE);
                paymentData.setToken(creditCard.getToken());
                paymentData.setUniqueNumberIdentifier(creditCard.getUniqueNumberIdentifier());
            }
            return paymentData;
        }
        return null;
    }

    protected static BraintreeTransactionEntryPaymentData convertPaymentInfo(final BrainTreeTransaction transaction) {
        final BraintreeTransactionEntryPaymentData paymentData = new BraintreeTransactionEntryPaymentData();
        if (transaction.getPaymentMethodSnapshot() != null && BraintreeConstants.CREDIT_CARD_DETAILS
            .equalsIgnoreCase(transaction.getPaymentMethodSnapshot().get__typename())) {
            final BrainTreePaymentMethodSnapshot details = transaction.getPaymentMethodSnapshot();

            paymentData.setCardholderName(details.getCardholderName());
            paymentData.setCardType(details.getBrandCode());
            paymentData
                .setCreditCardNumber(String.format("%s******%s", details.getBin(), details.getLast4()));
            paymentData
                .setExpirationDate(String.format("%s/%s", details.getExpirationMonth(), details.getExpirationYear()));
            paymentData.setPaymentType(BraintreeConstants.CREDIT_CARD_PAYMENT_TYPE);
            if (transaction.getPaymentMethod() != null) {
                paymentData.setToken(transaction.getPaymentMethod().getLegacyId());
                paymentData.setGraphQLToken(transaction.getPaymentMethod().getId());
            }
            paymentData.setUniqueNumberIdentifier(details.getUniqueNumberIdentifier());

            return paymentData;
        }
        return null;
    }

    protected static BraintreeTransactionEntryPayPalData convertPaymentPayPalInfo(final Transaction transaction) {
        final BraintreeTransactionEntryPayPalData payPalData = new BraintreeTransactionEntryPayPalData();
        if (InstrumentType.PAYPAL_PAYMENT_INSTRUMENT_TYPE.equals(transaction.getPaymentInstrumentType())) {
            final PayPalDetails payPalDetails = transaction.getPayPalDetails();
            if (payPalDetails != null) {
                payPalData.setToken(payPalDetails.getToken());
                payPalData.setAuthorizationUniqueTransactionID(payPalDetails.getAuthorizationId());
                payPalData.setPayeeEmail(payPalDetails.getPayeeEmail());
                payPalData.setPayerFirstName(payPalDetails.getPayerFirstName());
                payPalData.setPayerLastName(payPalDetails.getPayerLastName());
                payPalData.setPayerID(payPalDetails.getPayerId());
                payPalData.setPaymentID(payPalDetails.getPaymentId());
                payPalData.setPayPalCaptureID(payPalDetails.getCaptureId());
                payPalData.setPayPalCustomField(payPalDetails.getCustomField());
                payPalData.setPayPalDebugID(payPalDetails.getDebugId());
                payPalData.setPayPalRefundID(payPalDetails.getRefundId());
                payPalData.setPayPalSellerProtectionStatus(payPalDetails.getSellerProtectionStatus());
                payPalData.setPaymentType(BraintreeConstants.PAYPAL_PAYMENT_TYPE_NAME);
            }
            return payPalData;
        }
        return null;
    }

    protected static BraintreeTransactionEntryPayPalData convertPaymentPayPalInfo(
        final BrainTreeTransaction transaction) {
        final BraintreeTransactionEntryPayPalData payPalData = new BraintreeTransactionEntryPayPalData();
        if (transaction.getPaymentMethodSnapshot() != null && BraintreeConstants.PAYPAL_TRANSACTION_DETAILS
            .equalsIgnoreCase(transaction.getPaymentMethodSnapshot().get__typename())) {
            final BrainTreePaymentMethodSnapshot methodSnapshot = transaction.getPaymentMethodSnapshot();
            if (transaction.getPaymentMethod() != null) {
                payPalData.setToken(transaction.getPaymentMethod().getLegacyId());
                payPalData.setGraphQLToken(transaction.getPaymentMethod().getId());
            }
            payPalData.setAuthorizationUniqueTransactionID(methodSnapshot.getAuthorizationId());
            final BrainTreePayPalAccountDetails payer = methodSnapshot.getPayer();
            if (payer != null) {
                payPalData.setPayerEmail(payer.getEmail());
                payPalData.setPayerFirstName(payer.getFirstName());
                payPalData.setPayerLastName(payer.getLastName());
                payPalData.setPayerID(payer.getPayerId());
            }

            if (methodSnapshot.getPayee() != null) {
                payPalData.setPayeeEmail(methodSnapshot.getPayee().getEmail());
            }
            payPalData.setPaymentID(methodSnapshot.getPaymentId());
            payPalData.setPayPalCaptureID(methodSnapshot.getCaptureId());
            payPalData.setPayPalCustomField(methodSnapshot.getCustomField());
            payPalData.setPayPalRefundID(methodSnapshot.getRefundId());
            payPalData.setPayPalSellerProtectionStatus(methodSnapshot.getSellerProtectionStatus());
            payPalData.setPaymentType(BraintreeConstants.PAYPAL_PAYMENT_TYPE_NAME);
            return payPalData;
        }
        return null;
    }

    protected static BraintreeTransactionOriginEntryData convertOriginalTransactionInfo(final Transaction transaction) {
        final BraintreeTransactionOriginEntryData entryData = new BraintreeTransactionOriginEntryData();
        //TODO: find merchant, for now - just EMPTY
        entryData.setMerchant(StringUtils.EMPTY);
        entryData.setMerchantAccount(transaction.getMerchantAccountId());
        entryData.setProcessorAuthorizationCode(transaction.getProcessorAuthorizationCode());
        entryData.setSettlementBatch(transaction.getSettlementBatchId());
        entryData.setStatus(transaction.getStatus().name());
        entryData.setCvvResponse(transaction.getCvvResponseCode());
        entryData.setAmount(formedAmount(transaction.getAmount(), transaction.getCurrencyIsoCode()));
        if (transaction.getCreatedAt() != null) {
            entryData.setTransactionDate(formedDate(transaction.getCreatedAt()));
        }
        if (StringUtils.isNotBlank(transaction.getAvsErrorResponseCode())) {
            entryData.setAvsResponse(transaction.getAvsErrorResponseCode());
        } else {
            entryData.setAvsResponse(String.format("%s %s", transaction.getAvsPostalCodeResponseCode(),
                transaction.getAvsStreetAddressResponseCode()));
        }
        if (transaction.getRefundedTransactionId() != null) {
            entryData.setRefund(TRANSACTION_REFUND_SIGN);
        }
        if (transaction.getRiskData() != null) {
            entryData.setRiskDecision(transaction.getRiskData().getDecision());
        }
        return entryData;
    }

    protected static BraintreeTransactionOriginEntryData convertOriginalTransactionInfo(
        final BrainTreeTransaction transaction) {
        final BraintreeTransactionOriginEntryData entryData = new BraintreeTransactionOriginEntryData();
        //TODO: find merchant, for now - just EMPTY
        entryData.setMerchant(StringUtils.EMPTY);
        entryData.setMerchantAccount(transaction.getMerchantAccountId());
        entryData.setStatus(transaction.getStatus().name());
        final BrainTreePaymentStatusEvent authorizedEvent =
                findFirstEventByType(BraintreeConstants.GRAPHQL_SETTLED_EVENT_TYPE, transaction);
        if (authorizedEvent != null && authorizedEvent.getProcessorResponse() != null) {
            setAuthorizedEvent(authorizedEvent, entryData);
        }

        final BrainTreePaymentStatusEvent settledEvent =
                findFirstEventByType(BraintreeConstants.GRAPHQL_SETTLED_EVENT_TYPE, transaction);
        if (settledEvent != null) {
            entryData.setSettlementBatch(settledEvent.getSettlementBatchId());
        }

        if (transaction.getAmount() != null) {
            entryData.setAmount(formedAmount(new BigDecimal(transaction.getAmount().getValue()),
                transaction.getAmount().getCurrencyCode()));
        }

        if (transaction.getCreatedAt() != null) {
            entryData.setTransactionDate(formedDate(transaction.getCreatedAt()));
        }

        if (transaction.getRefunds() != null && transaction.getRefunds().size() > 0) {
            entryData.setRefund(TRANSACTION_REFUND_SIGN);
        }
        if (transaction.getRiskData() != null) {
            entryData.setRiskDecision(transaction.getRiskData().getDecision());
        }
        return entryData;
    }

    private static void setAuthorizedEvent(BrainTreePaymentStatusEvent authorizedEvent, BraintreeTransactionOriginEntryData entryData) {
        final BrainTreeTransactionAuthorizationProcessorResponse processorResponse = authorizedEvent
            .getProcessorResponse();
        entryData.setProcessorAuthorizationCode(processorResponse.getLegacyCode());
        entryData.setCvvResponse(processorResponse.getCvvResponse());
        final StringBuilder avs = new StringBuilder();
        if(processorResponse.getAsPostalCodeResponse() != null) {
            avs.append(processorResponse.getAsPostalCodeResponse())
                .append(" ");
        }
        if(processorResponse.getAvsStreetAddressResponse() != null) {
            avs.append(processorResponse.getAvsStreetAddressResponse());
        }
        entryData.setAvsResponse(avs.toString());
    }


    public static String formedName(final String firstName, final String lastName) {
        if (StringUtils.isNotBlank(firstName)) {
            if (StringUtils.isNotBlank(lastName)) {
                return String.format("%s %s", firstName, lastName);
            }
            return firstName;
        }
        return StringUtils.EMPTY;
    }

    public static String formedPaymentInfo(final Transaction transaction) {
        final String paymentInstrumentType = transaction.getPaymentInstrumentType();

        if (InstrumentType.PAYPAL_PAYMENT_INSTRUMENT_TYPE.equals(paymentInstrumentType)) {
            final PayPalDetails payPalDetails = transaction.getPayPalDetails();
            if (payPalDetails != null) {
                return payPalDetails.getPayerEmail();
            }
        }
        if (InstrumentType.CREDIT_CARD_PAYMENT_INSTRUMENT_TYPE.equals(paymentInstrumentType)) {
            final CreditCard creditCard = transaction.getCreditCard();
            if (creditCard != null) {
                return String.format("%s******%s", creditCard.getBin(), creditCard.getLast4());
            }
        }
        return StringUtils.EMPTY;
    }

    public static String formedPaymentInfo(final BrainTreePaymentMethodSnapshot methodSnapshot) {
        if (methodSnapshot != null) {
            final String typename = methodSnapshot.get__typename();

            if (BraintreeConstants.PAYPAL_ACCOUNT_DETAILS.equalsIgnoreCase(typename)) {
                final BrainTreePayPalAccountDetails payer = methodSnapshot.getPayer();
                if (payer != null) {
                    return payer.getEmail();
                }
            }
            if (BraintreeConstants.CREDIT_CARD_DETAILS.equals(typename)) {
                return String.format("%s******%s", methodSnapshot.getBin(), methodSnapshot.getLast4());
            }
        }
        return StringUtils.EMPTY;
    }

    public static String formedAmount(final BigDecimal amount, final String currencyIsoCode) {
        return String.format("%s %s", amount, currencyIsoCode);
    }

    public static String formedDate(final Calendar date) {
        final Locale userLocale = JaloSession.getCurrentSession().getSessionContext().getLocale();
        final DateFormat dateFormat = new SimpleDateFormat(BraintreeConstants.TRANSACTION_SEARCH_DATE_FORMAT, userLocale);
        return dateFormat.format(date.getTime());
    }

    private static BrainTreePaymentStatusEvent findFirstEventByType(String typename, BrainTreeTransaction transaction) {
        for (final BrainTreePaymentStatusEvent event : transaction.getStatusHistory()) {
            if (event.get__typename().equalsIgnoreCase(typename)) {
                return event;
            }
        }
        return null;
    }
}
