package de.renew.draw.ui.api;

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

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import de.renew.draw.storables.ontology.Figure;
import de.renew.draw.storables.ontology.FigureEnumeration;
import de.renew.draw.ui.impl.services.SelectionServiceImpl;
import de.renew.draw.ui.ontology.ErrorState;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

class SelectionApiTest {

    private SelectionServiceImpl _mockedService;

    @BeforeEach
    void setUp() throws NoSuchFieldException, IllegalAccessException {
        _mockedService = mock(SelectionServiceImpl.class);
        Field serviceField = SelectionApi.class.getDeclaredField("_service");
        serviceField.setAccessible(true);
        serviceField.set(null, _mockedService);
    }

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

    @Test
    void testGetSelectedFigures() {
        //given
        Vector<Figure> testVector = new Vector<>();
        when(_mockedService.getSelectedFigures()).thenReturn(testVector);
        //when
        Vector<Figure> returnedVector = SelectionApi.getSelectedFigures();
        //then
        verify(_mockedService).getSelectedFigures();
        assertThat(returnedVector).isEqualTo(testVector);
    }

    @Test
    void testGetSelectedFiguresZOrdered() {
        //given
        Vector<Figure> testVector = new Vector<>();
        when(_mockedService.getSelectedFiguresZOrdered()).thenReturn(testVector);
        //when
        Vector<Figure> returnedVector = SelectionApi.getSelectedFiguresZOrdered();
        //then
        verify(_mockedService).getSelectedFiguresZOrdered();
        assertThat(returnedVector).isEqualTo(testVector);
    }

    @Test
    void testAddToSelectionSingleFigure() {
        //given
        Figure figure = mock(Figure.class);
        //when
        SelectionApi.addToSelection(figure);
        //then
        verify(_mockedService).addToSelection(figure);
    }

    @Test
    void testAddToSelectionAllCollection() {
        //given
        Collection<Figure> figureCollection = mock(Collection.class);
        //when
        SelectionApi.addToSelectionAll(figureCollection);
        //then
        verify(_mockedService).addToSelectionAll(figureCollection);
    }

    @Test
    void testAddToSelectionAllEnumeration() {
        //given
        FigureEnumeration figureEnumeration = mock(FigureEnumeration.class);
        //when
        SelectionApi.addToSelectionAll(figureEnumeration);
        //then
        verify(_mockedService).addToSelectionAll(figureEnumeration);
    }

    @Test
    void testSelectionInvalidateHandles() {
        //when
        SelectionApi.selectionInvalidateHandles();
        //then
        verify(_mockedService).selectionInvalidateHandles();
    }

    @ParameterizedTest
    @ValueSource(booleans = { true, false })
    void testSelectOffendingElements(boolean value) {
        //given
        ErrorState errorState = mock(ErrorState.class);
        when(_mockedService.selectOffendingElements(errorState)).thenReturn(value);
        //when
        boolean returnValue = SelectionApi.selectOffendingElements(errorState);
        //then
        verify(_mockedService).selectOffendingElements(errorState);
        assertThat(returnValue).isEqualTo(value);
    }

    @ParameterizedTest
    @ValueSource(ints = { 1, 1000, 10, 30, 22, 0 })
    void testGetSelectionCount(int number) {
        //given
        when(_mockedService.getSelectionCount()).thenReturn(number);
        //when
        int detectedNumber = SelectionApi.getSelectionCount();
        //then
        Assertions.assertThat(detectedNumber).isEqualTo(number);
    }

    @Test
    void testClearSelection() {
        //given/when
        SelectionApi.clearSelection();
        //then
        verify(_mockedService).clearSelection();
    }
}