package com.braintreeocc.validators;

import com.braintree.enums.BrainTreePaymentMethod;
import de.hybris.bootstrap.annotations.UnitTest;
import de.hybris.platform.commercefacades.order.data.CCPaymentInfoData;
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 org.springframework.validation.Errors;
import org.springframework.validation.Validator;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.never;

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

    private static final String ACCOUNT_HOLDER_NAME = "accountHolderName";
    private static final String CARD_TYPE = "cardType";
    private static final String CART_NUMBER = "cardNumber";
    private static final String START_MONTH = "10";
    private static final String START_YEAR = "2023";
    private static final String EXPIRY_MONTH = "11";
    private static final String EXPIRY_YEAR = "2026";
    private static final String WRONG_START_MONTH = "11";
    private static final String WRONG_START_YEAR = "2029";
    private static final String WRONG_EXPIRY_MONTH = "12";
    private static final String WRONG_EXPIRY_YEAR = "2026";
    private static final String START_MONTH_KEY = "startMonth";
    private static final String ERROR_CODE = "payment.startDate.invalid";

    @Mock
    CCPaymentInfoData target;
    @Mock
    private Errors errors;
    @Mock
    private Validator paymentAddressValidator;

    @Spy
    @InjectMocks
    private BrainTreePaymentInfoValidator unit;

    @Test
    public void shouldNotFailValidationWhenCorrectExpiryDate() {
        when(target.getSubscriptionId()).thenReturn(BrainTreePaymentMethod.CREDITCARD.getCode());
        when(target.getExpiryMonth()).thenReturn(EXPIRY_MONTH);
        when(target.getExpiryYear()).thenReturn(EXPIRY_YEAR);
        when(target.getStartMonth()).thenReturn(START_MONTH);
        when(target.getStartYear()).thenReturn(START_YEAR);
        when(errors.getFieldValue(CARD_TYPE)).thenReturn(CARD_TYPE);
        when(errors.getFieldValue(ACCOUNT_HOLDER_NAME)).thenReturn(ACCOUNT_HOLDER_NAME);
        when(errors.getFieldValue(CART_NUMBER)).thenReturn(CART_NUMBER);

        unit.validate(target, errors);

        verify(target, times(3)).getSubscriptionId();
        verify(target, times(2)).getExpiryMonth();
        verify(target,  times(2)).getExpiryYear();
        verify(target,  times(2)).getStartMonth();
        verify(target,  times(2)).getStartYear();
        verify(errors).getFieldValue(CARD_TYPE);
        verify(errors).getFieldValue(ACCOUNT_HOLDER_NAME);
        verify(errors).getFieldValue(CART_NUMBER);
        verify(errors, never()).rejectValue(START_MONTH_KEY, ERROR_CODE);
        verify(paymentAddressValidator).validate(target, errors);
    }

    @Test
    public void shouldFailValidationWhenWrongExpiryDate() {
        when(target.getSubscriptionId()).thenReturn(BrainTreePaymentMethod.CREDITCARD.getCode());
        when(target.getExpiryMonth()).thenReturn(WRONG_EXPIRY_MONTH);
        when(target.getExpiryYear()).thenReturn(WRONG_EXPIRY_YEAR);
        when(target.getStartMonth()).thenReturn(WRONG_START_MONTH);
        when(target.getStartYear()).thenReturn(WRONG_START_YEAR);

        unit.validate(target, errors);

        verify(target, times(3)).getSubscriptionId();
        verify(target,  times(2)).getExpiryMonth();
        verify(target,  times(2)).getExpiryYear();
        verify(target,  times(2)).getStartMonth();
        verify(target,  times(2)).getStartYear();
        verify(errors).rejectValue(START_MONTH_KEY, ERROR_CODE);
        verify(paymentAddressValidator).validate(target, errors);
    }

    @Test
    public void doNothingWhenWrongPaymentMethod() {
        when(target.getSubscriptionId()).thenReturn(BrainTreePaymentMethod.VENMOACCOUNT.getCode());

        unit.validate(target, errors);

        verify(errors, never()).rejectValue(START_MONTH_KEY, ERROR_CODE);
        verify(paymentAddressValidator, never()).validate(target, errors);
    }

    @Test
    public void shouldReturnTrueIfPassedSupportedClass() {
        boolean isSupported = unit.supports(target.getClass());

        assertTrue(isSupported);
    }

    @Test
    public void shouldReturnFalseIfPassedUnsupportedClass() {
        boolean isSupported = unit.supports(Object.class);

        assertFalse(isSupported);
    }
}
