package com.braintree.populators;

import com.braintree.command.result.BrainTreeFindTransactionResult;
import com.braintree.converters.utils.BraintreeTransactionConverterUtils;
import com.braintree.enums.BraintreePaymentTransactionStatus;
import com.braintree.hybris.data.BraintreeRefundData;
import com.braintree.hybris.data.BraintreeStatusEventData;
import com.braintree.hybris.data.BraintreeTransactionData;
import com.braintree.hybris.data.BraintreeTransactionEntryData;
import com.braintree.hybris.data.BraintreeTransactionEntryDetailData;
import com.braintree.util.GenericBuilder;
import com.braintreegateway.Customer;
import com.braintreegateway.PayPalDetails;
import com.braintreegateway.ResourceCollection;
import com.braintreegateway.StatusEvent;
import com.braintreegateway.Transaction;
import de.hybris.platform.converters.Populator;
import de.hybris.platform.servicelayer.dto.converter.ConversionException;
import org.apache.commons.lang.StringUtils;

import java.util.ArrayList;
import java.util.List;

public class BraintreeTransactionPopulator implements
    Populator<BrainTreeFindTransactionResult, BraintreeTransactionData> {

    @Override
    public void populate(final BrainTreeFindTransactionResult brainTreeFindTransactionResult,
        final BraintreeTransactionData braintreeTransactionData) throws ConversionException {
        final ResourceCollection<Transaction> transactions = brainTreeFindTransactionResult.getTransactions();

        final List<BraintreeTransactionEntryData> transactionEntries = new ArrayList<BraintreeTransactionEntryData>();

        for (final Transaction transaction : transactions) {
            if (transaction != null) {
                final BraintreeTransactionEntryData braintreeTransactionEntryData = new BraintreeTransactionEntryData();
                braintreeTransactionEntryData.setId(transaction.getId());
                braintreeTransactionEntryData
                    .setDate(getFormedDate(transaction));
                braintreeTransactionEntryData
                    .setPaymentInfo(BraintreeTransactionConverterUtils.formedPaymentInfo(transaction));
                braintreeTransactionEntryData.setAmount(BraintreeTransactionConverterUtils
                    .formedAmount(transaction.getAmount(), transaction.getCurrencyIsoCode()));
                braintreeTransactionEntryData.setCurrencyIsoCode(transaction.getCurrencyIsoCode());
                braintreeTransactionEntryData.setTotal(transaction.getAmount());

                final PayPalDetails payPalDetails = transaction.getPayPalDetails();
                if (payPalDetails != null) {
                    braintreeTransactionEntryData.setRefundId(payPalDetails.getRefundId());
                    braintreeTransactionEntryData.setCaptureId(payPalDetails.getCaptureId());
                }

                final Customer customer = transaction.getCustomer();
                if (customer != null) {
                    braintreeTransactionEntryData.setCustomer(BraintreeTransactionConverterUtils
                        .formedName(customer.getFirstName(), customer.getLastName()));
                }

                if (transaction.getStatus() != null) {
                    braintreeTransactionEntryData.setStatus(transaction.getStatus().name());
                }
                if (transaction.getType() != null) {
                    braintreeTransactionEntryData.setType(transaction.getType().name());
                }
                if (transaction.getRiskData() != null) {
                    braintreeTransactionEntryData.setRiskDecision(transaction.getRiskData().getDecision());
                }
                braintreeTransactionEntryData
                    .setDetails(convertDetails(transaction));
                transactionEntries.add(braintreeTransactionEntryData);
                braintreeTransactionEntryData.setPaymentInstrumentType(transaction.getPaymentInstrumentType());
                braintreeTransactionEntryData.setIdGraphQL(transaction.getGraphQLId());

                if (transaction.getRefundIds() != null && !transaction.getRefundIds().isEmpty()) {
                    setRefunds(transaction, braintreeTransactionEntryData);
                }

                List<BraintreeStatusEventData> statusEventDataList = new ArrayList<>();
                if (transaction.getStatusHistory() != null) {
                    setStatusHistory(transaction, statusEventDataList);
                }
                braintreeTransactionEntryData.setStatusHistory(statusEventDataList);

                if (StringUtils.isNotBlank(transaction.getRefundedTransactionId())){
                    braintreeTransactionEntryData.setRefundedTransaction(GenericBuilder.of(BraintreeTransactionEntryData::new)
                            .with(BraintreeTransactionEntryData::setId, transaction.getRefundedTransactionId())
                            .build());
                }
            }
        }
        braintreeTransactionData.setTransactionEntries(transactionEntries);
    }

    private static void setRefunds(Transaction transaction, BraintreeTransactionEntryData braintreeTransactionEntryData) {
        List<BraintreeRefundData> refundeDataList = new ArrayList<>();
        for (String refundId : transaction.getRefundIds()) {
            BraintreeRefundData refundData = new BraintreeRefundData();
            refundData.setRequestId(refundId);
            refundeDataList.add(refundData);
        }
        braintreeTransactionEntryData.setRefundIds(refundeDataList);
    }

    private static void setStatusHistory(Transaction transaction, List<BraintreeStatusEventData> statusEventDataList) {
        for (StatusEvent statusHistory: transaction.getStatusHistory()) {
            BraintreeStatusEventData statusEventData = new BraintreeStatusEventData();
            statusEventData.setStatus(BraintreePaymentTransactionStatus.valueOf(statusHistory.getStatus().name()));
            statusEventData.setTimestamp(statusHistory.getTimestamp().getTime());
            statusEventDataList.add(statusEventData);
        }
    }

    protected String getFormedDate(Transaction transaction) {
        return BraintreeTransactionConverterUtils.formedDate(transaction.getCreatedAt());
    }

    protected BraintreeTransactionEntryDetailData convertDetails(Transaction transaction){
        return BraintreeTransactionConverterUtils.convertDetails(transaction);
    }

}
