package com.braintree.util;

import com.braintree.command.result.BrainTreeBillingAddressResult;
import com.braintree.command.result.BrainTreeCreatePaymentMethodResult;
import com.braintree.command.result.BrainTreePaymentDetailsResult;
import com.braintree.constants.BraintreeConstants;
import com.braintree.enums.BrainTreeCardType;
import com.braintree.enums.BrainTreePaymentMethod;
import com.braintree.hybris.data.graphql.commands.response.BrainTreePaymentMethodDetails;
import com.braintree.hybris.data.graphql.commands.response.BrainTreePaymentMethodOrigin;
import com.braintreegateway.Address;
import de.hybris.bootstrap.annotations.UnitTest;
import org.apache.commons.lang.StringUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.Optional;

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


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

    private static final String LAST_4 = "1111";
    public static final String MASK = "**************";
    public static final String ID = "ID";
    public static final String COMPANY = "COMPANY";
    public static final String ALPHA_2 = "ALPHA_2";
    public static final String ALPHA_3 = "ALPHA_3";
    public static final String STREET_ADDRESS = "STREET_ADDRESS";
    public static final String EXTENDED_ADDRESS = "EXTENDED_ADDRESS";
    public static final String REGION = "REGION";
    public static final String LOCATION = "LOCATION";
    public static final String POSTAL_CODE = "POSTAL_CODE";
    public static final String PHONE_NUMBER = "PHONE_NUMBER";
    public static final String FIRST_NAME = "FIRST_NAME";
    public static final String LAST_NAME = "LAST_NAME";
    public static final String TOKEN = "TOKEN";
    public static final String GRAPH_QL_TOKEN = "GRAPH_QL_TOKEN";
    public static final String IMAGE_URL = "IMAGE_URL";
    public static final String EMAIL = "EMAIL";
    public static final String MONTH = "01";
    public static final String YEAR = "35";
    public static final String CARD_NUMBER = "CARD_NUMBER";
    public static final String CARD_HOLDER_NAME = "CARD_HOLDER_NAME";
    public static final String ROUTING_NUMBER = "ROUTING_NUMBER";
    private static final String PAY_PAL_ACCOUNT_DETAILS = "PayPalAccountDetails";
    private static final String VENMO_ACCOUNT_DETAILS = "VenmoAccountDetails";
    private static final String US_BANK_ACCOUNT_DETAILS = "UsBankAccountDetails";
    private static final String CREDIT_CARD_DETAILS = "CreditCardDetails";
    private static final String VISA_CHECKOUT = "VISA_CHECKOUT";
    private static final String APPLE_PAY = "APPLE_PAY";
    private static final String GOOGLE_PAY = "GOOGLE_PAY";
    private static final String INVALID_ORIGIN = "InvalidOrigin";
    private static final String INVALID_TYPE_NAME = "InvalidTypeName";

    @Test
    public void shouldReturnTrueForIsCreditCardPayment() {
        assertTrue(BrainTreeUtils.isCreditCardPayment(BrainTreePaymentMethod.CREDITCARD.getCode()));
    }

    @Test
    public void shouldReturnFalseForIsCreditCardPayment() {
        assertFalse(BrainTreeUtils.isCreditCardPayment(BrainTreePaymentMethod.PAYPAL.getCode()));
    }

    @Test
    public void shouldReturnTrueForCreditCardPaymentInIsPaymentSupportThreeDS() {
        assertTrue(BrainTreeUtils.isPaymentSupportThreeDS(BrainTreePaymentMethod.CREDITCARD.getCode()));
    }

    @Test
    public void shouldReturnTrueForGooglePaymentInIsPaymentSupportThreeDS() {
        assertTrue(BrainTreeUtils.isPaymentSupportThreeDS(BrainTreePaymentMethod.ANDROIDPAYCARD.getCode()));
    }

    @Test
    public void shouldReturnTrueForSrcPaymentInIsPaymentSupportThreeDSForSaved() {
        assertTrue(BrainTreeUtils.isSavedPaymentSupportThreeDS(BrainTreePaymentMethod.VISACHECKOUTCARD.getCode()));
    }
    @Test
    public void shouldReturnTrueForGooglePaymentInIsPaymentSupportThreeDSForSaved() {
        assertTrue(BrainTreeUtils.isSavedPaymentSupportThreeDS(BrainTreePaymentMethod.ANDROIDPAYCARD.getCode()));
    }
    @Test
    public void shouldReturnTrueForCreditCardPaymentInIsPaymentSupportThreeDSForSaved() {
        assertTrue(BrainTreeUtils.isSavedPaymentSupportThreeDS(BrainTreePaymentMethod.CREDITCARD.getCode()));
    }
    @Test
    public void shouldReturnFalseForPayPalPaymentInIsPaymentSupportThreeDSForSaved() {
        assertFalse(BrainTreeUtils.isSavedPaymentSupportThreeDS(BrainTreePaymentMethod.PAYPALACCOUNT.getCode()));
    }

    @Test
    public void shouldReturnFalseForAllPaymentsInIsPaymentSupportThreeDS() {
        assertFalse(BrainTreeUtils.isPaymentSupportThreeDS(BrainTreePaymentMethod.PAYPAL.getCode()));
    }

    @Test
    public void shouldReturnTrueForPayPalExpressInIsPayPalPayment() {
        assertTrue(BrainTreeUtils.isPayPalPayment(BrainTreePaymentMethod.BRAINTREEPAYPALEXPRESS.getCode()));
    }

    @Test
    public void shouldReturnTrueForPayPalAccountInIsPayPalPayment() {
        assertTrue(BrainTreeUtils.isPayPalPayment(BrainTreePaymentMethod.PAYPALACCOUNT.getCode()));
    }

    @Test
    public void shouldReturnTrueForPayPalInIsPayPalPayment() {
        assertTrue(BrainTreeUtils.isPayPalPayment(BrainTreePaymentMethod.PAYPAL.getCode()));
    }

    @Test
    public void shouldReturnFalseForAllPaymentsInIsPayPalPayment() {
        assertFalse(BrainTreeUtils.isPayPalPayment(BrainTreePaymentMethod.CREDITCARD.getCode()));
    }

    @Test
    public void shouldReturnTrueForIsUsBankAccountPayment() {
        assertTrue(BrainTreeUtils.isUsBankAccountPayment(BrainTreePaymentMethod.USBANKACCOUNT.getCode()));
    }

    @Test
    public void shouldReturnFalseForIsUsBankAccountPayment() {
        assertFalse(BrainTreeUtils.isUsBankAccountPayment(BrainTreePaymentMethod.PAYPAL.getCode()));
    }

    @Test
    public void shouldReturnTrueForIsVenmoPayment() {
        assertTrue(BrainTreeUtils.isVenmoPayment(BrainTreePaymentMethod.VENMOACCOUNT.getCode()));
    }

    @Test
    public void shouldReturnFalseForIsVenmoPayment() {
        assertFalse(BrainTreeUtils.isVenmoPayment(BrainTreePaymentMethod.PAYPAL.getCode()));
    }

    @Test
    public void shouldReturnTrueForIsGooglePayment() {
        assertTrue(BrainTreeUtils.isGooglePayment(BrainTreePaymentMethod.ANDROIDPAYCARD.getCode()));
    }

    @Test
    public void shouldReturnFalseForIsGooglePayment() {
        assertFalse(BrainTreeUtils.isGooglePayment(BrainTreePaymentMethod.PAYPAL.getCode()));
    }

    @Test
    public void shouldReturnTrueForIsSrcPayment() {
        assertTrue(BrainTreeUtils.isSrcPayment(BrainTreePaymentMethod.VISACHECKOUTCARD.getCode()));
    }

    @Test
    public void shouldReturnFalseForIsSrcPayment() {
        assertFalse(BrainTreeUtils.isSrcPayment(BrainTreePaymentMethod.PAYPAL.getCode()));
    }

    @Test
    public void shouldReturnTrueForIsApplePayPayment() {
        assertTrue(BrainTreeUtils.isApplePayPayment(BrainTreePaymentMethod.APPLEPAYCARD.getCode()));
    }

    @Test
    public void shouldReturnFalseForIsApplePayPayment() {
        assertFalse(BrainTreeUtils.isApplePayPayment(BrainTreePaymentMethod.PAYPAL.getCode()));
    }

    @Test
    public void shouldReturnTrueForIsLPMPayment() {
        assertTrue(BrainTreeUtils.isLPMPayment(BrainTreePaymentMethod.LOCALPAYMENT.getCode()));
    }

    @Test
    public void shouldReturnFalseForIsLPMPayment() {
        assertFalse(BrainTreeUtils.isLPMPayment(BrainTreePaymentMethod.PAYPAL.getCode()));
    }

    @Test
    public void shouldReturnTrueForIsIntentSale() {
        assertTrue(BrainTreeUtils.isIntentSale(BraintreeConstants.PayPalIntent.PAYPAL_INTENT_SALE));
    }

    @Test
    public void shouldReturnFalseForIsIntentSale() {
        assertFalse(BrainTreeUtils.isIntentSale(StringUtils.EMPTY));
    }

    @Test
    public void shouldReturnTrueForIsIntentAuthorize() {
        assertTrue(BrainTreeUtils.isIntentAuthorize(BraintreeConstants.PayPalIntent.PAYPAL_INTENT_AUTHORIZE));
    }

    @Test
    public void shouldReturnFalseForIsIntentAuthorize() {
        assertFalse(BrainTreeUtils.isIntentAuthorize(StringUtils.EMPTY));
    }

    @Test
    public void shouldFormatCardNumber() {
        assertEquals(MASK + LAST_4, BrainTreeUtils.formatCardNumber(LAST_4));
    }

    @Test
    public void shouldConvertRestBrainTreeAddress() {
        Address source = mock(Address.class);

        when(source.getId()).thenReturn(ID);
        when(source.getCompany()).thenReturn(COMPANY);
        when(source.getCountryCodeAlpha2()).thenReturn(ALPHA_2);
        when(source.getCountryCodeAlpha3()).thenReturn(ALPHA_3);
        when(source.getStreetAddress()).thenReturn(STREET_ADDRESS);
        when(source.getExtendedAddress()).thenReturn(EXTENDED_ADDRESS);
        when(source.getRegion()).thenReturn(REGION);
        when(source.getLocality()).thenReturn(LOCATION);
        when(source.getPostalCode()).thenReturn(POSTAL_CODE);
        when(source.getPhoneNumber()).thenReturn(PHONE_NUMBER);
        when(source.getFirstName()).thenReturn(FIRST_NAME);
        when(source.getLastName()).thenReturn(LAST_NAME);

        final BrainTreeBillingAddressResult result = BrainTreeUtils.convertRestBrainTreeAddress(source);

        assertEquals(ID, result.getAddressId());
        assertEquals(COMPANY, result.getCompany());
        assertEquals(ALPHA_2, result.getCountyCode());
        assertEquals(ALPHA_3, result.getCountyCodeAlpha3());
        assertEquals(STREET_ADDRESS, result.getStreetAddress());
        assertEquals(EXTENDED_ADDRESS, result.getExtendedAddress());
        assertEquals(REGION, result.getRegion());
        assertEquals(LOCATION, result.getLocality());
        assertEquals(POSTAL_CODE, result.getPostalCode());
        assertEquals(PHONE_NUMBER, result.getPhone());
        assertEquals(FIRST_NAME, result.getFirstName());
        assertEquals(LAST_NAME, result.getLastName());

    }

    @Test
    public void shouldNotConvertRestBrainTreeAddress() {
        Address source = null;

        BrainTreeBillingAddressResult result = BrainTreeUtils.convertRestBrainTreeAddress(source);

        assertNull(result.getAddressId());
        assertNull(result.getCompany());
        assertNull(result.getCountyCode());
        assertNull(result.getCountyCodeAlpha3());
        assertNull(result.getStreetAddress());
        assertNull(result.getExtendedAddress());
        assertNull(result.getRegion());
        assertNull(result.getLocality());
        assertNull(result.getPostalCode());
        assertNull(result.getPhone());
        assertNull(result.getFirstName());
        assertNull(result.getLastName());
    }

    @Test
    public void shouldConvertPaymentDetailsToPaymentMethodResult() {
        BrainTreePaymentDetailsResult paymentMethod = mock(BrainTreePaymentDetailsResult.class);

        when(paymentMethod.getPaymentProvider()).thenReturn(BrainTreePaymentMethod.PAYPAL.getCode());
        when(paymentMethod.getPaymentMethodToken()).thenReturn(TOKEN);
        when(paymentMethod.getPaymentMethodGraphQLToken()).thenReturn(GRAPH_QL_TOKEN);
        when(paymentMethod.getImageUrl()).thenReturn(IMAGE_URL);
        when(paymentMethod.getEmail()).thenReturn(EMAIL);
        when(paymentMethod.getCardType()).thenReturn(BrainTreeCardType.VISA.toString());
        when(paymentMethod.getExpirationMonth()).thenReturn(MONTH);
        when(paymentMethod.getExpirationYear()).thenReturn(YEAR);
        when(paymentMethod.getCardNumber()).thenReturn(CARD_NUMBER);
        when(paymentMethod.getLast4()).thenReturn(LAST_4);
        when(paymentMethod.getCardholderName()).thenReturn(CARD_HOLDER_NAME);
        when(paymentMethod.getVerified()).thenReturn(true);
        when(paymentMethod.getRoutingNumber()).thenReturn(ROUTING_NUMBER);

        final BrainTreeCreatePaymentMethodResult result = BrainTreeUtils.convertPaymentDetailsToPaymentMethodResult(paymentMethod);

        assertEquals(BrainTreePaymentMethod.PAYPAL.getCode(), result.getPaymentProvider());
        assertEquals(TOKEN, result.getPaymentMethodToken());
        assertEquals(GRAPH_QL_TOKEN, result.getPaymentMethodGraphQLToken());
        assertEquals(IMAGE_URL, result.getImageSource());
        assertEquals(EMAIL, result.getEmail());
        assertEquals(BrainTreeCardType.VISA.toString(), result.getCardType());
        assertEquals(MONTH, result.getExpirationMonth());
        assertEquals(YEAR, result.getExpirationYear());
        assertEquals(CARD_NUMBER, result.getCardNumber());
        assertEquals(LAST_4, result.getLast4());
        assertEquals(CARD_HOLDER_NAME, result.getCardholderName());
        assertTrue(result.getVerified());
        assertEquals(ROUTING_NUMBER, result.getRoutingNumber());
    }

    @Test
    public void shouldNotConvertRoutingNumberInConvertPaymentDetailsToPaymentMethodResult() {
        BrainTreePaymentDetailsResult paymentMethod = mock(BrainTreePaymentDetailsResult.class);

        final BrainTreeCreatePaymentMethodResult result = BrainTreeUtils.convertPaymentDetailsToPaymentMethodResult(paymentMethod);

        assertNull(result.getRoutingNumber());
    }

    @Test
    public void shouldReturnPayPalPaymentProvider(){
        final BrainTreePaymentMethodDetails paymentMethodDetails = new BrainTreePaymentMethodDetails();
        paymentMethodDetails.set__typename(PAY_PAL_ACCOUNT_DETAILS);

        final Optional<BrainTreePaymentMethod> brainTreePaymentMethod = BrainTreeUtils.determinePaymentProvider(paymentMethodDetails);

        assertEquals(BrainTreePaymentMethod.PAYPALACCOUNT, brainTreePaymentMethod.get());
    }
    @Test
    public void shouldReturnVenmoPaymentProvider(){
        final BrainTreePaymentMethodDetails paymentMethodDetails = new BrainTreePaymentMethodDetails();
        paymentMethodDetails.set__typename(VENMO_ACCOUNT_DETAILS);

        final Optional<BrainTreePaymentMethod> brainTreePaymentMethod = BrainTreeUtils.determinePaymentProvider(paymentMethodDetails);

        assertEquals(BrainTreePaymentMethod.VENMOACCOUNT, brainTreePaymentMethod.get());
    }

    @Test
    public void shouldReturnUSBankPaymentProvider(){
        final BrainTreePaymentMethodDetails paymentMethodDetails = new BrainTreePaymentMethodDetails();
        paymentMethodDetails.set__typename(US_BANK_ACCOUNT_DETAILS);

        final Optional<BrainTreePaymentMethod> brainTreePaymentMethod = BrainTreeUtils.determinePaymentProvider(paymentMethodDetails);

        assertEquals(BrainTreePaymentMethod.USBANKACCOUNT, brainTreePaymentMethod.get());
    }

    @Test
    public void shouldReturnCreditCardPaymentProvider(){
        final BrainTreePaymentMethodDetails paymentMethodDetails = new BrainTreePaymentMethodDetails();
        paymentMethodDetails.set__typename(CREDIT_CARD_DETAILS);

        final Optional<BrainTreePaymentMethod> brainTreePaymentMethod = BrainTreeUtils.determinePaymentProvider(paymentMethodDetails);

        assertEquals(BrainTreePaymentMethod.CREDITCARD, brainTreePaymentMethod.get());
    }

    @Test
    public void shouldReturnVisaCheckoutPaymentProvider(){
        final BrainTreePaymentMethodDetails paymentMethodDetails = new BrainTreePaymentMethodDetails();
        final BrainTreePaymentMethodOrigin paymentMethodOrigin = new BrainTreePaymentMethodOrigin();
        paymentMethodOrigin.setType(VISA_CHECKOUT);
        paymentMethodDetails.setOrigin(paymentMethodOrigin);
        paymentMethodDetails.set__typename(CREDIT_CARD_DETAILS);

        final Optional<BrainTreePaymentMethod> brainTreePaymentMethod = BrainTreeUtils.determinePaymentProvider(paymentMethodDetails);

        assertEquals(BrainTreePaymentMethod.VISACHECKOUTCARD, brainTreePaymentMethod.get());
    }

    @Test
    public void shouldReturnApplePayPaymentProvider(){
        final BrainTreePaymentMethodDetails paymentMethodDetails = new BrainTreePaymentMethodDetails();
        final BrainTreePaymentMethodOrigin paymentMethodOrigin = new BrainTreePaymentMethodOrigin();
        paymentMethodOrigin.setType(APPLE_PAY);
        paymentMethodDetails.setOrigin(paymentMethodOrigin);
        paymentMethodDetails.set__typename(CREDIT_CARD_DETAILS);

        final Optional<BrainTreePaymentMethod> brainTreePaymentMethod = BrainTreeUtils.determinePaymentProvider(paymentMethodDetails);

        assertEquals(BrainTreePaymentMethod.APPLEPAYCARD, brainTreePaymentMethod.get());
    }

    @Test
    public void shouldReturnAndroidPayPaymentProvider(){
        final BrainTreePaymentMethodDetails paymentMethodDetails = new BrainTreePaymentMethodDetails();
        final BrainTreePaymentMethodOrigin paymentMethodOrigin = new BrainTreePaymentMethodOrigin();
        paymentMethodOrigin.setType(GOOGLE_PAY);
        paymentMethodDetails.setOrigin(paymentMethodOrigin);
        paymentMethodDetails.set__typename(CREDIT_CARD_DETAILS);

        final Optional<BrainTreePaymentMethod> brainTreePaymentMethod = BrainTreeUtils.determinePaymentProvider(paymentMethodDetails);

        assertEquals(BrainTreePaymentMethod.ANDROIDPAYCARD, brainTreePaymentMethod.get());
    }

    @Test
    public void shouldReturnNullWithInvalidOrigin(){
        final BrainTreePaymentMethodDetails paymentMethodDetails = new BrainTreePaymentMethodDetails();
        final BrainTreePaymentMethodOrigin paymentMethodOrigin = new BrainTreePaymentMethodOrigin();
        paymentMethodOrigin.setType(INVALID_ORIGIN);
        paymentMethodDetails.setOrigin(paymentMethodOrigin);
        paymentMethodDetails.set__typename(CREDIT_CARD_DETAILS);

        final Optional<BrainTreePaymentMethod> brainTreePaymentMethod = BrainTreeUtils.determinePaymentProvider(paymentMethodDetails);

        assertFalse(brainTreePaymentMethod.isPresent());
    }

    @Test
    public void shouldReturnNullWithInvalidTypeName(){
        final BrainTreePaymentMethodDetails paymentMethodDetails = new BrainTreePaymentMethodDetails();
        paymentMethodDetails.set__typename(INVALID_TYPE_NAME);

        final Optional<BrainTreePaymentMethod> brainTreePaymentMethod = BrainTreeUtils.determinePaymentProvider(paymentMethodDetails);

        assertFalse(brainTreePaymentMethod.isPresent());
    }

}
