package com.braintree.populators;

import com.braintree.enums.BraintreePaymentTransactionStatus;
import com.braintree.hybris.data.BrainTreeGraphQLTransactionData;
import com.braintree.hybris.data.BraintreeTransactionEntryData;
import com.braintree.hybris.data.graphql.commands.response.BrainTreeMonetaryAmount;
import com.braintree.hybris.data.graphql.commands.response.BrainTreePageInfo;
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.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.hybris.data.graphql.commands.response.BrainTreeRefundDetails;
import com.braintree.hybris.data.graphql.commands.response.BrainTreeTransaction;
import de.hybris.bootstrap.annotations.UnitTest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;

@UnitTest
@RunWith(MockitoJUnitRunner.class)
public class BraintreeGraphQLRefundPopulatorTest {

    public static final String TIME_STAMP = "TimeStamp";
    public static final String END_CURSOR = "EndCursor";
    public static final String DATE = "Date";
    public static final String LEGACY_ID = "LegacyId";
    public static final String ID = "Id";
    public static final String PAY_PAL_ACCOUNT_DETAILS = "PayPalAccountDetails";
    public static final String PAYER_EMAIL = "PayerEmail";
    public static final String USD = "USD";
    public static final String AMOUNT = "100";
    public static final String CAPTURE_ID = "CaptureId";
    public static final String REFUND_ID = "RefundId";

    @InjectMocks
    @Spy
    private BraintreeGraphQLRefundPopulator unit;

    @Mock
    private BrainTreeRefundConnection brainTreeRefundConnection;
    @Mock
    private BrainTreePageInfo pageInfo;
    @Mock
    private BrainTreeRefundConnectionEdge edge;
    @Mock
    private List<BrainTreeRefundConnectionEdge> edgeList;
    @Mock
    private Iterator<BrainTreeRefundConnectionEdge> edgeIterator;
    @Mock
    private BrainTreeTransaction refundTransaction;
    @Mock
    private List<BrainTreePaymentStatusEvent> paymentStatusEventList;
    @Mock
    private BrainTreePaymentStatusEvent paymentStatusEvent;
    @Mock
    private Iterator<BrainTreePaymentStatusEvent> paymentStatusEventIterator;
    @Mock
    private BrainTreeRefund node;
    @Mock
    private BrainTreePaymentMethodSnapshot paymentMethodSnapshot;
    @Mock
    private BrainTreePayPalAccountDetails brainTreePayPalAccountDetails;
    @Mock
    private BrainTreeMonetaryAmount brainTreeMonetaryAmount;
    @Mock
    private BrainTreeRefundDetails refundDetails;
    @Mock
    private Calendar calendar;

    @Test
    public void shouldPopulateBraintreeGraphQLRefundTest() {
        BrainTreeGraphQLTransactionData target = new BrainTreeGraphQLTransactionData();

        doReturn(DATE).when(unit).getFormedDate(node);
        doReturn(calendar).when(unit).getParseDateTime(TIME_STAMP);

        when(brainTreeRefundConnection.getPageInfo()).thenReturn(pageInfo);
        when(pageInfo.isHasNextPage()).thenReturn(true);
        when(pageInfo.getEndCursor()).thenReturn(END_CURSOR);
        when(brainTreeRefundConnection.getEdges()).thenReturn(edgeList);
        when(edgeList.iterator()).thenReturn(edgeIterator);
        when(edgeIterator.hasNext()).thenReturn(true, false);
        when(edgeIterator.next()).thenReturn(edge);
        when(edge.getNode()).thenReturn(node);
        when(node.getPaymentMethodSnapshot()).thenReturn(paymentMethodSnapshot);
        when(node.getLegacyId()).thenReturn(LEGACY_ID);
        when(node.getId()).thenReturn(ID);
        when(node.getDetails()).thenReturn(refundDetails);
        when(refundDetails.getRefundId()).thenReturn(REFUND_ID);
        when(paymentMethodSnapshot.get__typename()).thenReturn(PAY_PAL_ACCOUNT_DETAILS);
        when(paymentMethodSnapshot.getPayer()).thenReturn(brainTreePayPalAccountDetails);
        when(brainTreePayPalAccountDetails.getEmail()).thenReturn(PAYER_EMAIL);
        when(node.getAmount()).thenReturn(brainTreeMonetaryAmount);
        when(brainTreeMonetaryAmount.getCurrencyCode()).thenReturn(USD);
        when(brainTreeMonetaryAmount.getValue()).thenReturn(AMOUNT);
        when(paymentMethodSnapshot.getCaptureId()).thenReturn(CAPTURE_ID);
        when(node.getStatus()).thenReturn(BrainTreePaymentStatus.AUTHORIZED);
        when(node.getStatusHistory()).thenReturn(paymentStatusEventList);
        when(paymentStatusEventList.iterator()).thenReturn(paymentStatusEventIterator);
        when(paymentStatusEventIterator.hasNext()).thenReturn(true, false);
        when(paymentStatusEventIterator.next()).thenReturn(paymentStatusEvent);
        when(paymentStatusEvent.getStatus()).thenReturn(BrainTreePaymentStatus.AUTHORIZED);
        when(paymentStatusEvent.getTimestamp()).thenReturn(TIME_STAMP);
        when(node.getRefundedTransaction()).thenReturn(refundTransaction);
        when(refundTransaction.getLegacyId()).thenReturn(LEGACY_ID);
        when(refundTransaction.getId()).thenReturn(ID);

        unit.populate(brainTreeRefundConnection, target);

        BraintreeTransactionEntryData transactionEntryData = target.getTransactionData().getTransactionEntries().get(0);
        assertTrue(target.getHasNextPage());
        assertEquals(END_CURSOR, target.getEndCursor());
        assertEquals(LEGACY_ID, transactionEntryData.getId());
        assertEquals(ID, transactionEntryData.getIdGraphQL());
        assertEquals(DATE, transactionEntryData.getDate());
        assertEquals(PAYER_EMAIL, transactionEntryData.getPaymentInfo());
        assertEquals(String.format("%s %s", AMOUNT, USD), transactionEntryData.getAmount());
        assertEquals(new BigDecimal(AMOUNT), transactionEntryData.getTotal());
        assertEquals(CAPTURE_ID, transactionEntryData.getCaptureId());
        assertEquals(BraintreePaymentTransactionStatus.AUTHORIZED, transactionEntryData.getStatusHistory().get(0).getStatus());
        assertEquals(calendar.getTime(), transactionEntryData.getStatusHistory().get(0).getTimestamp());
    }

    @Test
    public void shouldPopulateBraintreeGraphQLRefundWhenStatusHistoryIsNullAndTransactionsIsNull() {
        BrainTreeGraphQLTransactionData target = new BrainTreeGraphQLTransactionData();

        doReturn(DATE).when(unit).getFormedDate(node);

        when(brainTreeRefundConnection.getPageInfo()).thenReturn(pageInfo);
        when(pageInfo.isHasNextPage()).thenReturn(true);
        when(pageInfo.getEndCursor()).thenReturn(END_CURSOR);
        when(brainTreeRefundConnection.getEdges()).thenReturn(edgeList);
        when(edgeList.iterator()).thenReturn(edgeIterator);
        when(edgeIterator.hasNext()).thenReturn(true, false);
        when(edgeIterator.next()).thenReturn(edge);
        when(edge.getNode()).thenReturn(node);
        when(node.getPaymentMethodSnapshot()).thenReturn(paymentMethodSnapshot);
        when(node.getLegacyId()).thenReturn(LEGACY_ID);
        when(node.getId()).thenReturn(ID);
        when(node.getDetails()).thenReturn(refundDetails);
        when(refundDetails.getRefundId()).thenReturn(REFUND_ID);
        when(paymentMethodSnapshot.get__typename()).thenReturn(PAY_PAL_ACCOUNT_DETAILS);
        when(paymentMethodSnapshot.getPayer()).thenReturn(brainTreePayPalAccountDetails);
        when(brainTreePayPalAccountDetails.getEmail()).thenReturn(PAYER_EMAIL);
        when(node.getAmount()).thenReturn(brainTreeMonetaryAmount);
        when(brainTreeMonetaryAmount.getCurrencyCode()).thenReturn(USD);
        when(brainTreeMonetaryAmount.getValue()).thenReturn(AMOUNT);
        when(paymentMethodSnapshot.getCaptureId()).thenReturn(CAPTURE_ID);
        when(node.getStatus()).thenReturn(BrainTreePaymentStatus.GATEWAY_REJECTED);
        when(node.getStatusHistory()).thenReturn(null);
        when(node.getRefundedTransaction()).thenReturn(null);

        unit.populate(brainTreeRefundConnection, target);

        BraintreeTransactionEntryData transactionEntryData = target.getTransactionData().getTransactionEntries().get(0);
        assertTrue(target.getHasNextPage());
        assertEquals(END_CURSOR, target.getEndCursor());
        assertEquals(LEGACY_ID, transactionEntryData.getId());
        assertEquals(ID, transactionEntryData.getIdGraphQL());
        assertEquals(DATE, transactionEntryData.getDate());
        assertEquals(PAYER_EMAIL, transactionEntryData.getPaymentInfo());
        assertEquals(String.format("%s %s", AMOUNT, USD), transactionEntryData.getAmount());
        assertEquals(new BigDecimal(AMOUNT), transactionEntryData.getTotal());
        assertEquals(CAPTURE_ID, transactionEntryData.getCaptureId());
        assertEquals(0, transactionEntryData.getStatusHistory().size());
        assertEquals(0, transactionEntryData.getStatusHistory().size());
    }
}
