package de.renew.draw.ui.api;

import java.lang.reflect.Field;
import java.util.Vector;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import de.renew.draw.storables.ontology.Drawing;
import de.renew.draw.storables.ontology.Figure;
import de.renew.draw.ui.api.services.ErrorService;
import de.renew.draw.ui.impl.services.ErrorServiceImpl;
import de.renew.draw.ui.ontology.ErrorState;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class ErrorApiTest {

    private static final String DUMMY_STRING = "Dummy String";
    private static final int DUMMY_INT = 123;
    private static final Drawing DUMMY_DRAWING = mock(Drawing.class);
    private static final Figure DUMMY_FIGURE = mock(Figure.class);
    private static final Object DUMMY_OBJECT = mock(Object.class);

    private ErrorService _mockedService;
    private ErrorState _expectedErrorState;
    private Vector<Figure> _figures;

    @BeforeEach
    void setUp() throws NoSuchFieldException, IllegalAccessException {
        _mockedService = mock(ErrorServiceImpl.class);
        Field serviceField = ErrorApi.class.getDeclaredField("_service");
        serviceField.setAccessible(true);
        serviceField.set(null, _mockedService);
        _expectedErrorState = mock(ErrorState.class);
        _figures = new Vector<>();
        _figures.add(DUMMY_FIGURE);
    }

    @AfterEach
    void tearDown() {
        _mockedService = null;
        _expectedErrorState = null;
        _figures = null;
    }

    @Test
    void testCreateErrorStateWithSingleFigure() {
        // given
        when(
            _mockedService
                .createErrorState(anyString(), anyString(), any(Drawing.class), any(Figure.class)))
            .thenReturn(_expectedErrorState);

        // when
        ErrorState actualErrorState =
            ErrorApi.createErrorState(DUMMY_STRING, DUMMY_STRING, DUMMY_DRAWING, DUMMY_FIGURE);

        // then
        assertThat(actualErrorState).isEqualTo(_expectedErrorState);
        verify(_mockedService)
            .createErrorState(DUMMY_STRING, DUMMY_STRING, DUMMY_DRAWING, DUMMY_FIGURE);
    }

    @SuppressWarnings("unchecked")
    @Test
    void testCreateErrorStateWithMultipleFigures() {
        // given
        when(
            _mockedService
                .createErrorState(anyString(), anyString(), any(Drawing.class), any(Vector.class)))
            .thenReturn(_expectedErrorState);

        // when
        ErrorState actualErrorState =
            ErrorApi.createErrorState(DUMMY_STRING, DUMMY_STRING, DUMMY_DRAWING, _figures);

        // then
        assertThat(actualErrorState).isEqualTo(_expectedErrorState);
        verify(_mockedService)
            .createErrorState(DUMMY_STRING, DUMMY_STRING, DUMMY_DRAWING, _figures);
    }

    @SuppressWarnings("unchecked")
    @Test
    void testCreateErrorStateWithMultipleFiguresAndObject() {
        // given
        when(
            _mockedService.createErrorState(
                anyString(), anyInt(), anyInt(), any(Drawing.class), any(Figure.class),
                any(Vector.class), any(Object.class)))
            .thenReturn(_expectedErrorState);

        // when
        ErrorState actualErrorState = ErrorApi.createErrorState(
            DUMMY_STRING, DUMMY_INT, DUMMY_INT, DUMMY_DRAWING, DUMMY_FIGURE, _figures,
            DUMMY_OBJECT);

        // then
        assertThat(actualErrorState).isEqualTo(_expectedErrorState);
        verify(_mockedService).createErrorState(
            DUMMY_STRING, DUMMY_INT, DUMMY_INT, DUMMY_DRAWING, DUMMY_FIGURE, _figures,
            DUMMY_OBJECT);
    }

    @Test
    void testCreateErrorStateWithSingleFigureAndObject() {
        // given
        when(
            _mockedService.createErrorState(
                anyString(), anyInt(), anyInt(), any(Drawing.class), any(Figure.class),
                any(Object.class)))
            .thenReturn(_expectedErrorState);

        // when
        ErrorState actualErrorState = ErrorApi.createErrorState(
            DUMMY_STRING, DUMMY_INT, DUMMY_INT, DUMMY_DRAWING, DUMMY_FIGURE, DUMMY_OBJECT);

        // then
        assertThat(actualErrorState).isEqualTo(_expectedErrorState);
        verify(_mockedService).createErrorState(
            DUMMY_STRING, DUMMY_INT, DUMMY_INT, DUMMY_DRAWING, DUMMY_FIGURE, DUMMY_OBJECT);
    }
}
