package com.braintree.commands.impl;

import com.braintree.command.request.BrainTreeFindMerchantAccountRequest;
import com.braintree.command.result.BrainTreeFindMerchantAccountResult;
import com.braintreegateway.BraintreeGateway;
import com.braintreegateway.MerchantAccount;
import com.braintreegateway.MerchantAccountGateway;
import com.braintreegateway.exceptions.NotFoundException;
import de.hybris.bootstrap.annotations.UnitTest;
import org.apache.log4j.Logger;
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 static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;

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

    private static final String MERCHANT_ACCOUNT_ID = "merchantAccountId";
    private static final String MERCHANT_TRANSACTION_CODE = "merchantTransactionCode";

    @Mock
    private Logger mockLogger;
    @Mock
    MerchantAccountGateway merchantAccountGateway;
    @Mock
    private BraintreeGateway mockGateway;
    @Spy
    @InjectMocks
    private DefaultBrainTreeFindMerchantAccountCommand findMerchantAccountCommand;

    @Test
    public void shouldReturnTrueWhenMerchantAccountExists() {
        BrainTreeFindMerchantAccountRequest request = createFindMerchantAccountRequest();
        MerchantAccount mockMerchantAccount = mock(MerchantAccount.class);

        doReturn(mockGateway).when(findMerchantAccountCommand).getBraintreeGateway();
        when(mockGateway.merchantAccount()).thenReturn(merchantAccountGateway);
        when(merchantAccountGateway.find(eq(request.getMerchantAccount()))).thenReturn(mockMerchantAccount);

        BrainTreeFindMerchantAccountResult result = findMerchantAccountCommand.perform(request);

        assertTrue(result.isMerchantAccountExist());
        verify(mockLogger, never()).error(anyString(), any(Exception.class));
    }

    @Test
    public void shouldReturnFalseWhenMerchantAccountNotFound() {
        BrainTreeFindMerchantAccountRequest request = createFindMerchantAccountRequest();

        doReturn(mockGateway).when(findMerchantAccountCommand).getBraintreeGateway();
        when(mockGateway.merchantAccount()).thenReturn(merchantAccountGateway);
        when(merchantAccountGateway.find(eq(request.getMerchantAccount()))).thenThrow(new NotFoundException("Merchant not found"));

        BrainTreeFindMerchantAccountResult result = findMerchantAccountCommand.perform(request);

        assertFalse(result.isSuccess());
        assertFalse(result.isMerchantAccountExist());
    }

    @Test
    public void shouldReturnFalseWhenMerchantAccountIsNull() {
        BrainTreeFindMerchantAccountRequest request = createFindMerchantAccountRequest();

        doReturn(mockGateway).when(findMerchantAccountCommand).getBraintreeGateway();
        when(mockGateway.merchantAccount()).thenReturn(merchantAccountGateway);
        when(merchantAccountGateway.find(eq(request.getMerchantAccount()))).thenReturn(null);

        BrainTreeFindMerchantAccountResult result = findMerchantAccountCommand.perform(request);

        assertFalse(result.isSuccess());
        assertFalse(result.isMerchantAccountExist());
    }

    @Test(expected = IllegalArgumentException.class)
    public void shouldThrowIllegalArgumentException() {
        BrainTreeFindMerchantAccountRequest request = createFindMerchantAccountRequest();

        doReturn(mockGateway).when(findMerchantAccountCommand).getBraintreeGateway();
        when(mockGateway.merchantAccount()).thenReturn(merchantAccountGateway);
        when(merchantAccountGateway.find(eq(request.getMerchantAccount()))).thenThrow(new IllegalArgumentException());

        findMerchantAccountCommand.perform(request);
    }

    private BrainTreeFindMerchantAccountRequest createFindMerchantAccountRequest() {
        BrainTreeFindMerchantAccountRequest merchantAccountRequest = new BrainTreeFindMerchantAccountRequest(MERCHANT_TRANSACTION_CODE);
        merchantAccountRequest.setMerchantAccount(MERCHANT_ACCOUNT_ID);
        return merchantAccountRequest;
    }
}
