package com.braintree.populators;

import com.braintree.converters.utils.BraintreeTransactionConverterUtils;
import com.braintree.enums.BraintreePaymentTransactionStatus;
import com.braintree.hybris.data.BrainTreeGraphQLTransactionData;
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.hybris.data.graphql.commands.response.BrainTreeCustomer;
import com.braintree.hybris.data.graphql.commands.response.BrainTreePaymentMethodSnapshot;
import com.braintree.hybris.data.graphql.commands.response.BrainTreePaymentStatus;
import com.braintree.hybris.data.graphql.commands.response.BrainTreePaymentStatusEvent;
import com.braintree.hybris.data.graphql.commands.response.BrainTreeRefund;
import com.braintree.hybris.data.graphql.commands.response.BrainTreeTransaction;
import com.braintree.hybris.data.graphql.commands.response.BrainTreeTransactionConnection;
import com.braintree.hybris.data.graphql.commands.response.BrainTreeTransactionConnectionEdge;
import de.hybris.platform.converters.Populator;
import de.hybris.platform.payment.dto.TransactionStatus;
import de.hybris.platform.servicelayer.dto.converter.ConversionException;

import javax.xml.bind.DatatypeConverter;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

/**
 * Populates BrainTreeGraphQLCustomerData from BrainTreeCustomerConnection.
 */
public class BraintreeGraphQLTransactionPopulator implements
        Populator<BrainTreeTransactionConnection, BrainTreeGraphQLTransactionData> {

    @Override
    public void populate(BrainTreeTransactionConnection source, BrainTreeGraphQLTransactionData target)
            throws ConversionException {

        target.setHasNextPage(source.getPageInfo().isHasNextPage());
        target.setEndCursor(source.getPageInfo().getEndCursor());

        BraintreeTransactionData transactionData = new BraintreeTransactionData();
        List<BraintreeTransactionEntryData> entryDataList = new ArrayList<>();

        for (BrainTreeTransactionConnectionEdge edge : source.getEdges()) {
            BrainTreeTransaction transaction = edge.getNode();
            if (transaction != null) {
                final BraintreeTransactionEntryData entryData = new BraintreeTransactionEntryData();
                final BrainTreePaymentMethodSnapshot paymentMethodSnapshot = transaction.getPaymentMethodSnapshot();
                entryData.setId(transaction.getLegacyId());
                entryData.setIdGraphQL(transaction.getId());
                entryData.setDate(getFormedDate(transaction));
                entryData.setPaymentInfo(
                        BraintreeTransactionConverterUtils.formedPaymentInfo(paymentMethodSnapshot));
                entryData.setAmount(BraintreeTransactionConverterUtils
                        .formedAmount(new BigDecimal(transaction.getAmount().getValue()),
                                transaction.getAmount().getCurrencyCode()));
                entryData.setCurrencyIsoCode(transaction.getAmount().getCurrencyCode());
                entryData.setTotal(new BigDecimal(transaction.getAmount().getValue()));
                entryData.setCaptureId(paymentMethodSnapshot.getCaptureId());

                BrainTreeCustomer customer = transaction.getCustomer();
                if (customer != null) {
                    entryData.setCustomer(BraintreeTransactionConverterUtils
                            .formedName(customer.getFirstName(), customer.getLastName()));
                }

                setTransactionStatus(transaction, entryData);

                if (transaction.getRiskData() != null) {
                    entryData.setRiskDecision(transaction.getRiskData().getDecision());
                }
                entryData.setDetails(getCoverDetails(transaction));

                if (transaction.getRefunds() != null && !transaction.getRefunds().isEmpty()) {
                    setRefunds(transaction, entryData);
                }

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

                entryDataList.add(entryData);
            }
        }
        transactionData.setTransactionEntries(entryDataList);
        target.setTransactionData(transactionData);
    }

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

    private static void setRefunds(BrainTreeTransaction transaction, BraintreeTransactionEntryData entryData) {
        List<BraintreeRefundData> refundeDataList = new ArrayList<>();
        for (BrainTreeRefund refund : transaction.getRefunds()) {
            BraintreeRefundData refundData = new BraintreeRefundData();
            refundData.setRequestIdGraphQL(refund.getId());
            refundData.setRequestId(refund.getLegacyId());
            refundeDataList.add(refundData);
        }
        entryData.setRefundIds(refundeDataList);
    }

    private void setTransactionStatus(BrainTreeTransaction transaction, BraintreeTransactionEntryData entryData) {
        BrainTreePaymentStatus transactionStatus = transaction.getStatus();
        if (transactionStatus != null) {
            if (transactionStatus.isSuccess()) {
                entryData.setStatus(TransactionStatus.ACCEPTED.name());
            } else {
                entryData.setStatus(transactionStatus.name());
            }
            entryData.setBraintreeTransactionStatus(transactionStatus.name());
        }
    }

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

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

    protected Calendar getParseDateTime(String timestamp) {
        return DatatypeConverter.parseDateTime(timestamp);
    }

}
