package com.braintree.populators;

import com.braintree.command.result.BrainTreeBillingAddressResult;
import com.braintree.command.result.BrainTreePaymentMethodResult;
import com.braintree.model.BrainTreePaymentInfoModel;
import de.hybris.bootstrap.annotations.UnitTest;
import de.hybris.platform.core.model.user.AddressModel;
import de.hybris.platform.servicelayer.dto.converter.Converter;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.Calendar;

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;

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

    private static final String PAY_PAL_PAYMENT_PROVIDER = "PayPal";
    private static final String CREDIT_CARD_PAYMENT_PROVIDER = "CreditCard";
    private static final String LAST_FOUR = "1234";
    private static final String EXPIRATION_MONTH = "ExpirationMonth";
    private static final String EXPIRATION_YEAR = "ExpirationYear";
    private static final String CARD_HOLDER_NAME = "CardHolderName";
    private static final String PAYMENT_METHOD_TOKEN = "PaymentMethodToken";
    private static final String GRAPH_QL_TOKEN = "GraphQLToken";
    private static final String IMAGE_SOURCE = "ImageSource";
    private static final String EMAIL = "Email";
    private static final String CUSTOMER_ID = "CustomerId";
    private static final String CARD_TYPE = "MasterCard";
    private static final String BIN = "4111";
    private static final String CARD_NUMBER = String.format("%s******%s", BIN, LAST_FOUR);

    @InjectMocks
    private BraintreeGraphQLPaymentMethodPopulator unit;

    @Mock
    private BrainTreePaymentMethodResult paymentMethodResult;
    @Mock
    private Calendar calendar;
    @Mock
    private BrainTreeBillingAddressResult billingAddressResult;
    @Mock
    private Converter<BrainTreeBillingAddressResult, AddressModel> braintreeAddressConverter;
    @Mock
    private AddressModel billingAddressModel;

    @Test
    public void shouldPopulatePayPalPaymentMethodResultToPaymentInfoModelTest(){
        BrainTreePaymentInfoModel target = new BrainTreePaymentInfoModel();

        when(paymentMethodResult.getPaymentMethodToken()).thenReturn(PAYMENT_METHOD_TOKEN);
        when(paymentMethodResult.getPaymentMethodGraphQLToken()).thenReturn(GRAPH_QL_TOKEN);
        when(paymentMethodResult.getImageSource()).thenReturn(IMAGE_SOURCE);
        when(paymentMethodResult.getPaymentProvider()).thenReturn(PAY_PAL_PAYMENT_PROVIDER);
        when(paymentMethodResult.getEmail()).thenReturn(EMAIL);
        when(paymentMethodResult.getCreatedAt()).thenReturn(calendar);
        when(paymentMethodResult.getCustomerId()).thenReturn(CUSTOMER_ID);
        when(paymentMethodResult.getExpirationMonth()).thenReturn(EXPIRATION_MONTH);
        when(paymentMethodResult.getExpirationYear()).thenReturn(EXPIRATION_YEAR);
        when(paymentMethodResult.getCardholderName()).thenReturn(CARD_HOLDER_NAME);
        when(paymentMethodResult.getBillingAddressResult()).thenReturn(billingAddressResult);
        when(braintreeAddressConverter.convert(billingAddressResult)).thenReturn(billingAddressModel);

        unit.populate(paymentMethodResult, target);

        assertEquals(PAYMENT_METHOD_TOKEN, target.getPaymentMethodToken());
        assertEquals(GRAPH_QL_TOKEN, target.getPaymentMethodGraphQLToken());
        assertEquals(IMAGE_SOURCE, target.getImageSource());
        assertEquals(PAY_PAL_PAYMENT_PROVIDER, target.getPaymentProvider());
        assertEquals(EMAIL, target.getPaymentInfo());
        assertEquals(CUSTOMER_ID, target.getCustomerId());
        assertEquals(EXPIRATION_MONTH, target.getExpirationMonth());
        assertEquals(EXPIRATION_YEAR, target.getExpirationYear());
        assertEquals(CARD_HOLDER_NAME, target.getCardholderName());
        assertEquals(billingAddressModel, target.getBillingAddress());
    }

    @Test
    public void shouldPopulateCreditCardPaymentMethodResultToPaymentInfoModelTest(){
        BrainTreePaymentInfoModel target = new BrainTreePaymentInfoModel();

        when(paymentMethodResult.getPaymentMethodToken()).thenReturn(PAYMENT_METHOD_TOKEN);
        when(paymentMethodResult.getPaymentMethodGraphQLToken()).thenReturn(GRAPH_QL_TOKEN);
        when(paymentMethodResult.getImageSource()).thenReturn(IMAGE_SOURCE);
        when(paymentMethodResult.getPaymentProvider()).thenReturn(CREDIT_CARD_PAYMENT_PROVIDER);
        when(paymentMethodResult.getBin()).thenReturn(BIN);
        when(paymentMethodResult.getLast4()).thenReturn(LAST_FOUR);
        when(paymentMethodResult.getCreatedAt()).thenReturn(calendar);
        when(paymentMethodResult.getCustomerId()).thenReturn(CUSTOMER_ID);
        when(paymentMethodResult.getCardType()).thenReturn(CARD_TYPE);
        when(paymentMethodResult.getExpirationMonth()).thenReturn(EXPIRATION_MONTH);
        when(paymentMethodResult.getExpirationYear()).thenReturn(EXPIRATION_YEAR);
        when(paymentMethodResult.getCardholderName()).thenReturn(CARD_HOLDER_NAME);
        when(paymentMethodResult.getBillingAddressResult()).thenReturn(billingAddressResult);
        when(braintreeAddressConverter.convert(billingAddressResult)).thenReturn(billingAddressModel);

        unit.populate(paymentMethodResult, target);

        assertEquals(PAYMENT_METHOD_TOKEN, target.getPaymentMethodToken());
        assertEquals(GRAPH_QL_TOKEN, target.getPaymentMethodGraphQLToken());
        assertEquals(IMAGE_SOURCE, target.getImageSource());
        assertEquals(CREDIT_CARD_PAYMENT_PROVIDER, target.getPaymentProvider());
        assertEquals(CUSTOMER_ID, target.getCustomerId());
        assertEquals(CARD_NUMBER, target.getPaymentInfo());
        assertEquals(CARD_NUMBER, target.getCardNumber());
        assertEquals(CARD_TYPE, target.getCardType().getCode());
        assertEquals(EXPIRATION_MONTH, target.getExpirationMonth());
        assertEquals(EXPIRATION_YEAR, target.getExpirationYear());
        assertEquals(CARD_HOLDER_NAME, target.getCardholderName());
        assertEquals(billingAddressModel, target.getBillingAddress());
    }

    @Test
    public void shouldDoNothingWhenTargetIsNull(){
        unit.populate(paymentMethodResult, null);

        verify(paymentMethodResult, never()).getPaymentMethod();
    }

    @Test
    public void shouldDoNothingWhenSourceIsNull(){
        final BrainTreePaymentInfoModel target = mock(BrainTreePaymentInfoModel.class);

        unit.populate(null, target);

        verify(target, never()).setCardType(any());
    }
}
