package com.braintree.graphql.commands.impl;

import com.braintree.command.result.BrainTreeTransactionResult;
import com.braintree.commands.impl.AbstractCommand;
import com.braintree.hybris.data.graphql.commands.response.BrainTreeTransaction;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.hybris.bootstrap.annotations.UnitTest;
import de.hybris.platform.payment.AdapterException;
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.Spy;
import org.mockito.runners.MockitoJUnitRunner;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import static com.braintree.constants.BraintreeConstants.ID_PARAMETER;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;

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

    private static final String DEFINITION_FILE_NAME = "searchTransactionById";
    private static final String TRANSACTION_ID = "transactionId";
    private static final String NODE = "node";
    private static final String RESULT_ERRORS = "errors";
    private static final String RESULT_DATA = "data";
    private static final String UNEXISTING_TRANSACTION = "unexisting transaction";

    @Mock
    private Converter<BrainTreeTransaction, BrainTreeTransactionResult> transactionResultConverter;
    @Mock
    private Map<String, Object> graphQLCallResult;
    @Mock
    private ArrayList<Map<String, Object>> mapErrors;
    @Mock
    private Map<String, Object> data;
    @Mock
    private Object node;
    @Mock
    private ObjectMapper objectMapper;

    @InjectMocks
    @Spy
    private DefaultBrainTreeGraphQLGetTransactionByIdCommand graphQLGetTransactionByIdCommand;

    @Test
    public void shouldFindTransactionWhenItIsExist() throws IOException {
        Map<String, Object> map = new HashMap<>();
        map.put(ID_PARAMETER, TRANSACTION_ID);
        BrainTreeTransaction transactionData = new BrainTreeTransaction();
        BrainTreeTransactionResult transactionResult = new BrainTreeTransactionResult();

        doReturn(graphQLCallResult).when((AbstractCommand) graphQLGetTransactionByIdCommand).makeGraphQlCall(DEFINITION_FILE_NAME, map);
        when(graphQLCallResult.get(RESULT_ERRORS)).thenReturn(null);
        when(graphQLCallResult.get(RESULT_DATA)).thenReturn(data);
        when(data.get(NODE)).thenReturn(node);
        when(objectMapper.convertValue(node, BrainTreeTransaction.class)).thenReturn(transactionData);
        when(transactionResultConverter.convert(transactionData)).thenReturn(transactionResult);

        BrainTreeTransactionResult actual = graphQLGetTransactionByIdCommand.perform(TRANSACTION_ID);

        assertEquals(transactionResult, actual);
    }

    @Test(expected = AdapterException.class)
    public void shouldThrowExceptionWhenThereIsErrorInResponse() {
        graphQLGetTransactionByIdCommand.perform(UNEXISTING_TRANSACTION);
    }

    @Test(expected = AdapterException.class)
    public void shouldThrowAdapterExceptionWhenMapContainsErrors() throws IOException {
        Map<String, Object> map = new HashMap<>();
        map.put(ID_PARAMETER, TRANSACTION_ID);

        doReturn(graphQLCallResult).when((AbstractCommand) graphQLGetTransactionByIdCommand).makeGraphQlCall(DEFINITION_FILE_NAME, map);
        when(graphQLCallResult.get(RESULT_ERRORS)).thenReturn(mapErrors);

        graphQLGetTransactionByIdCommand.perform(TRANSACTION_ID);

    }


}
