package com.braintree.graphql.commands.impl;

import com.braintree.hybris.data.graphql.commands.request.BrainTreeExchangeLegacyIdRequest;
import com.braintreegateway.ValidationError;
import com.braintreegateway.ValidationErrorCode;
import de.hybris.bootstrap.annotations.UnitTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;

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

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.verify;

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

    private static final String DATA_MAP_KEY = "data";
    private static final String DEFINITION_FILE_NAME = "idFromLegacyId";
    private static final String LEGACY_ID = "legacyIdValue";
    private static final String TYPE = "typeValue";
    private static final String LEGACY_ID_PARAMETER = "legacyId";
    private static final String TYPE_PARAMETER = "type";
    private static final String ID_FROM_LEGACY_PARAMETER = "idFromLegacyId";
    private static final String ID_FROM_LEGACY_PARAMETER_VALUE = "idFromLegacyParameterValue";
    private static final String RESULT_ERRORS = "errors";
    private static final String ERROR_MESSAGE = "errorMessage";
    private static final String ERROR_ATTRIBUTE = "errorAttribute";
    private static final String ERROR_KEY_MAP = "error";

    @Spy
    @InjectMocks
    private DefaultBrainTreeGraphQLExchangeLegacyIdCommand command;

    @Captor
    private ArgumentCaptor<Map<String, Object>> variables;

    private Map<String, Object> mapResult;
    private BrainTreeExchangeLegacyIdRequest request;

    @Before
    public void setUp() throws IOException {
        request = new BrainTreeExchangeLegacyIdRequest();
        request.setLegacyId(LEGACY_ID);
        request.setType(TYPE);

        mapResult = new HashMap<>();
        mapResult.put(DATA_MAP_KEY, new HashMap<>());
        doReturn(mapResult).when(command).makeGraphQlCall(eq(DEFINITION_FILE_NAME), any());
    }

    @Test
    public void shouldCreateVariablesMap() throws IOException {
        //when
        command.perform(request);

        //then
        verify(command).makeGraphQlCall(eq(DEFINITION_FILE_NAME), variables.capture());
        Map<String, Object> inputResult = variables.getValue();
        assertNotNull(inputResult);
        assertEquals(LEGACY_ID, inputResult.get(LEGACY_ID_PARAMETER));
        assertEquals(TYPE, inputResult.get(TYPE_PARAMETER));
    }

    @Test
    public void shouldReturnIdFromLegacyParameterIfGraphQLResponseSuccessful() throws IOException {
        //given
        ((Map) mapResult.get(DATA_MAP_KEY)).put(ID_FROM_LEGACY_PARAMETER, ID_FROM_LEGACY_PARAMETER_VALUE);

        //when
        String commandResult = command.perform(request);

        //then
        verify(command).makeGraphQlCall(eq(DEFINITION_FILE_NAME), any());
        assertEquals(ID_FROM_LEGACY_PARAMETER_VALUE, commandResult);
    }

    @Test(expected = IllegalArgumentException.class)
    public void shouldThrowErrorIfGraphQLResponseContainsError() throws IOException {
        //given
        ValidationError validationError =
                new ValidationError(ERROR_ATTRIBUTE, ValidationErrorCode.UNKNOWN_VALIDATION_ERROR, ERROR_MESSAGE);
        Map<String, Object> errorMap = Map.of(ERROR_KEY_MAP, validationError);
        List<Map<String, Object>> errorList = new ArrayList<>();
        errorList.add(errorMap);
        mapResult.put(RESULT_ERRORS, errorList);

        //when
        command.perform(request);

        //then
        verify(command).makeGraphQlCall(eq(DEFINITION_FILE_NAME), any());
    }

    @Test(expected = IllegalArgumentException.class)
    public void shouldThrowErrorIfGraphQLRequestFails() throws IOException {
        //given
        doThrow(IOException.class).when(command).makeGraphQlCall(any(), any());

        //when
        command.perform(request);

        //then
        verify(command).makeGraphQlCall(eq(DEFINITION_FILE_NAME), any());
    }


}
