package com.braintree.converters.populators;

import com.braintree.enums.BrainTreeCardType;
import com.braintree.enums.ExpirationStatus;
import com.braintree.model.BrainTreePaymentInfoModel;
import de.hybris.bootstrap.annotations.UnitTest;
import de.hybris.platform.commercefacades.order.data.CCPaymentInfoData;
import de.hybris.platform.commercefacades.user.data.AddressData;
import de.hybris.platform.core.PK;
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.text.SimpleDateFormat;
import java.util.Date;

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

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

    private static final String CARD_NUMBER = "CARD_NUMBER";
    private static final String EXPIRATION_YEAR = "EXPIRATION_YEAR";
    private static final String EXPIRATION_MONTH = "EXPIRATION_MONTH";
    private static final String IMG_SOURCE = "IMG_SOURCE";
    private static final String PAYMENT_PROVIDER = "PAYMENT_PROVIDER";
    private static final String CREDIT_CARD_PAYMENT_PROVIDER = "CreditCard";
    private static final boolean SAVED = true;
    private static final String VISA = "Visa";
    private static final String EXPIRATION_STATUS_NOT_APPLICABLE = "NOT_APPLICABLE";
    private static final String FUNDING_SOURCE = "FUNDING_SOURCE";
    private static final String PAYMENT_METHOD_TOKEN = "PAYMENT_METHOD_TOKENs";
    private static final String CARD_HOLDER_NAME = "CARD_HOLDER_NAME";
    private static final String PAYER = "PAYER";
    private static final String NONCE = "NONCE";
    private static final String CUSTOMER_ID = "CUSTOMER_ID";
    private static final String LAST_4 = "LAST_4";
    private static final String ROUTING_NUMBER = "ROUTING_NUMBER";

    private static final long PK_LONG_VALUE = 100000;
    private static final PK PK_VALUE = PK.fromLong(PK_LONG_VALUE);
    @Mock
    private Converter<AddressModel, AddressData> addressConverter;
    @Mock
    private BrainTreePaymentInfoModel model;
    @Mock
    private AddressModel addressModel;

    @InjectMocks
    private final BrainTreePaymentInfoPopulator brainTreePaymentInfoPopulator = new BrainTreePaymentInfoPopulator();

    @Test
    public void shouldPopulateCCPaymentInfoData() {
        // given
        final CCPaymentInfoData data = new CCPaymentInfoData();

        when(model.getPk()).thenReturn(PK_VALUE);
        when(model.getCardNumber()).thenReturn(CARD_NUMBER);
        when(model.getExpirationMonth()).thenReturn(EXPIRATION_MONTH);
        when(model.getExpirationYear()).thenReturn(EXPIRATION_YEAR);
        when(model.getExpirationStatus()).thenReturn(ExpirationStatus.NOT_APPLICABLE);
        when(model.getImageSource()).thenReturn(IMG_SOURCE);
        when(model.getPaymentProvider()).thenReturn(PAYMENT_PROVIDER);
        when(model.getPaypalFundingSource()).thenReturn(FUNDING_SOURCE);
        when(model.isSaved()).thenReturn(SAVED);
        when(model.getPaymentMethodToken()).thenReturn(PAYMENT_METHOD_TOKEN);
        when(model.getCardholderName()).thenReturn(CARD_HOLDER_NAME);
        when(model.getPayer()).thenReturn(PAYER);
        when(model.getNonce()).thenReturn(NONCE);
        when(model.getCustomerId()).thenReturn(CUSTOMER_ID);
        when(model.getLast4()).thenReturn(LAST_4);
        when(model.getRoutingNumber()).thenReturn(ROUTING_NUMBER);

        // when
        brainTreePaymentInfoPopulator.populate(model, data);

        //then
        assertEquals(String.valueOf(PK_LONG_VALUE), data.getId());
        assertEquals(CARD_NUMBER, data.getCardNumber());
        assertEquals(EXPIRATION_MONTH, data.getExpiryMonth());
        assertEquals(EXPIRATION_YEAR, data.getExpiryYear());
        assertEquals(EXPIRATION_STATUS_NOT_APPLICABLE, data.getExpirationStatus());
        assertEquals(IMG_SOURCE, data.getAccountHolderName());
        assertEquals(PAYMENT_PROVIDER, data.getSubscriptionId());
        assertEquals(FUNDING_SOURCE, data.getPaypalFundingSource());
        assertTrue(data.isSaved());
        assertEquals(PAYMENT_METHOD_TOKEN, data.getPaymentMethodToken());
        assertEquals(CARD_HOLDER_NAME, data.getCardholderName());
        assertEquals(PAYER, data.getPayer());
        assertEquals(NONCE, data.getPaymentMethodNonce());
        assertEquals(CUSTOMER_ID, data.getCustomerId());
        assertEquals(LAST_4, data.getLast4());
        assertEquals(ROUTING_NUMBER, data.getRoutingNumber());
    }

    @Test
    public void shouldPopulateReminderMothToExpire() {
        // given
        final CCPaymentInfoData data = new CCPaymentInfoData();

        when(model.getPk()).thenReturn(PK_VALUE);

        when(model.getPaymentProvider()).thenReturn(CREDIT_CARD_PAYMENT_PROVIDER);
        when(model.getExpirationStatus()).thenReturn(ExpirationStatus.EXPIRE_SOON);

        SimpleDateFormat monthFormat = new SimpleDateFormat("MM");
        when(model.getExpirationMonth()).thenReturn(monthFormat.format(new Date()));

        SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy");
        when(model.getExpirationYear()).thenReturn(yearFormat.format(new Date()));

        // when
        brainTreePaymentInfoPopulator.populate(model, data);

        //then
        assertEquals(1, data.getReminderMonthToExpire());
    }

    @Test
    public void shouldPopulateCardType() {
        // given
        final CCPaymentInfoData data = new CCPaymentInfoData();

        when(model.getPk()).thenReturn(PK_VALUE);
        when(model.getExpirationStatus()).thenReturn(ExpirationStatus.NOT_APPLICABLE);

        when(model.getCardType()).thenReturn(BrainTreeCardType.VISA);

        // when
        brainTreePaymentInfoPopulator.populate(model, data);

        //then
        assertEquals(VISA, data.getCardType());
    }

    @Test
    public void shouldPopulateBillingAddress() {
        // given
        final CCPaymentInfoData data = new CCPaymentInfoData();
        final AddressData addressData = new AddressData();

        when(model.getPk()).thenReturn(PK_VALUE);
        when(model.getExpirationStatus()).thenReturn(ExpirationStatus.NOT_APPLICABLE);

        when(model.getBillingAddress()).thenReturn(addressModel);
        when(addressConverter.convert(addressModel)).thenReturn(addressData);

        // when
        brainTreePaymentInfoPopulator.populate(model, data);

        //then
        assertEquals(addressData, data.getBillingAddress());
    }

}
