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.BraintreeStatusEventData;
import com.braintree.hybris.data.BraintreeTransactionData;
import com.braintree.hybris.data.BraintreeTransactionEntryData;
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.BrainTreeRefundConnection;
import com.braintree.hybris.data.graphql.commands.response.BrainTreeRefundConnectionEdge;
import com.braintree.util.GenericBuilder;
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;
import java.util.Objects;

public class BraintreeGraphQLRefundPopulator implements
        Populator<BrainTreeRefundConnection, BrainTreeGraphQLTransactionData> {
    @Override
    public void populate(BrainTreeRefundConnection 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 (BrainTreeRefundConnectionEdge edge : source.getEdges()) {
            BrainTreeRefund transaction = edge.getNode();
            if (transaction != null) {
                final BraintreeTransactionEntryData entryData = new BraintreeTransactionEntryData();
                entryData.setId(transaction.getLegacyId());
                entryData.setIdGraphQL(transaction.getId());
                entryData.setDate(getFormedDate(transaction));
                entryData.setPaymentInfo(
                        BraintreeTransactionConverterUtils.formedPaymentInfo(transaction.getPaymentMethodSnapshot()));
                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(transaction.getPaymentMethodSnapshot().getCaptureId());
                entryData.setRefundId(transaction.getDetails().getRefundId());

                setTransactionStatus(transaction, entryData);

                List<BraintreeStatusEventData> statusEventDataList = new ArrayList<>();
                if (transaction.getStatusHistory() != null) {
                    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);
                    }
                }
                entryData.setStatusHistory(statusEventDataList);

                if (Objects.nonNull(transaction.getRefundedTransaction())) {
                    entryData.setRefundedTransaction(GenericBuilder.of(BraintreeTransactionEntryData::new)
                            .with(BraintreeTransactionEntryData::setId, transaction.getRefundedTransaction().getLegacyId())
                            .with(BraintreeTransactionEntryData::setIdGraphQL, transaction.getRefundedTransaction().getId())
                            .build());
                }

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

    private void setTransactionStatus(BrainTreeRefund 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(BrainTreeRefund transaction) {
        return BraintreeTransactionConverterUtils.formedDate(transaction.getCreatedAt());
    }

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

}
