package de.renew.draw.ui.api;

import java.awt.Frame;
import java.lang.reflect.Field;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JMenuItem;

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

import de.renew.draw.ui.impl.services.MenuServiceImpl;
import de.renew.draw.ui.ontology.MenuSectionPosition;
import de.renew.draw.ui.ontology.MenuSeparatorFactory;

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;

class MenuApiTest {

    public static final String DUMMY_STRING = "Dummy String";
    private static final int DUMMY_INT = 123;
    private static final JDialog DUMMY_DIALOG = new JDialog();
    private static final JMenuItem DUMMY_JMENUITEM = new JMenuItem(DUMMY_STRING);
    private static final Frame DUMMY_FRAME = new JFrame();
    private static final Runnable DUMMY_RUNNABLE = () -> {
    };

    private MenuServiceImpl _mockedService;

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

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

    @Test
    void testRegisterMenuWithParentAndMenu() {
        // given
        JMenuItem menu = mock(JMenuItem.class);

        // when
        MenuApi.registerMenu(DUMMY_STRING, menu);

        // then
        verify(_mockedService).registerMenu(DUMMY_STRING, menu);
    }

    @Test
    void testRegisterMenuWithParentAndMenuAndId() {
        // given
        String parent = DUMMY_STRING + "1";
        JMenuItem menu = mock(JMenuItem.class);
        String id = DUMMY_STRING + "2";

        // when
        MenuApi.registerMenu(parent, menu, id);

        // then
        verify(_mockedService).registerMenu(parent, menu, id);
    }

    @Test
    void testRegisterMenuWithParentAndSectionAndPosition() {
        // given
        JMenuItem menu = mock(JMenuItem.class);
        MenuSectionPosition position = MenuSectionPosition.BEGINNING;

        // when
        MenuApi.registerMenu(DUMMY_STRING, menu, DUMMY_INT, position);

        // then
        verify(_mockedService).registerMenu(DUMMY_STRING, menu, DUMMY_INT, position);
    }

    @Test
    void testUnregisterMenuWithMenu() {
        // given
        JMenuItem menu = mock(JMenuItem.class);

        // when
        MenuApi.unregisterMenu(menu);

        // then
        verify(_mockedService).unregisterMenu(menu);
    }

    @Test
    void testUnregisterMenuWithId() {
        // when
        MenuApi.unregisterMenu(DUMMY_STRING);

        // then
        verify(_mockedService).unregisterMenu(DUMMY_STRING);
    }

    @Test
    void testCreateTopLevelMenu() {
        // when
        MenuApi.createTopLevelMenu(DUMMY_STRING, DUMMY_INT);

        // then
        verify(_mockedService).createTopLevelMenu(DUMMY_STRING, DUMMY_INT);
    }

    @Test
    void testCreateMenuItemWithoutShortcut() {
        // given
        JMenuItem expectedMenuItem = mock(JMenuItem.class);
        when(_mockedService.createMenuItem(any(), any())).thenReturn(expectedMenuItem);

        // when
        JMenuItem actualMenuItem = MenuApi.createMenuItem(DUMMY_STRING, DUMMY_RUNNABLE);

        // then
        assertThat(actualMenuItem).isEqualTo(expectedMenuItem);
        verify(_mockedService).createMenuItem(DUMMY_STRING, DUMMY_RUNNABLE);
    }

    @Test
    void testCreateMenuItemWithShortcut() {
        // given
        JMenuItem expectedMenuItem = mock(JMenuItem.class);
        when(_mockedService.createMenuItem(any(), anyInt(), any())).thenReturn(expectedMenuItem);

        // when
        JMenuItem actualMenuItem = MenuApi.createMenuItem(DUMMY_STRING, DUMMY_INT, DUMMY_RUNNABLE);

        // then
        assertThat(actualMenuItem).isEqualTo(expectedMenuItem);
        verify(_mockedService).createMenuItem(DUMMY_STRING, DUMMY_INT, DUMMY_RUNNABLE);
    }

    @Test
    void testCreateMenuSeparatorFactory() {
        // given
        MenuSeparatorFactory expectedFactory = mock(MenuSeparatorFactory.class);
        when(_mockedService.createMenuSeparatorFactory(anyString())).thenReturn(expectedFactory);

        // when
        MenuSeparatorFactory actualFactory = MenuApi.createMenuSeparatorFactory(DUMMY_STRING);

        // then
        assertThat(actualFactory).isEqualTo(expectedFactory);
        verify(_mockedService).createMenuSeparatorFactory(DUMMY_STRING);
    }

    @Test
    void testCreateMenuSeparator() {
        // given
        JMenuItem expectedSeparator = mock(JMenuItem.class);
        when(_mockedService.createMenuSeparator(anyString())).thenReturn(expectedSeparator);

        // when
        JMenuItem actualSeparator = MenuApi.createMenuSeparator(DUMMY_STRING);

        // then
        assertThat(actualSeparator).isEqualTo(expectedSeparator);
        verify(_mockedService).createMenuSeparator(DUMMY_STRING);
    }

    @Test
    void testGetMenuNamePluginsMenu() {
        // given
        when(_mockedService.getMenuNamePluginsMenu()).thenReturn(DUMMY_STRING);

        // when
        String result = MenuApi.getMenuNamePluginsMenu();

        // then
        assertThat(result).isEqualTo(DUMMY_STRING);
        verify(_mockedService).getMenuNamePluginsMenu();
    }

    @Test
    void testGetMenuNamePlatformsMenu() {
        // given
        when(_mockedService.getMenuNamePlatformsMenu()).thenReturn(DUMMY_STRING);

        // when
        String result = MenuApi.getMenuNamePlatformsMenu();

        // then
        assertThat(result).isEqualTo(DUMMY_STRING);
        verify(_mockedService).getMenuNamePlatformsMenu();
    }

    @Test
    void testGetMenuNameFileMenu() {
        // given
        when(_mockedService.getMenuNameFileMenu()).thenReturn(DUMMY_STRING);

        // when
        String result = MenuApi.getMenuNameFileMenu();

        // then
        assertThat(result).isEqualTo(DUMMY_STRING);
        verify(_mockedService).getMenuNameFileMenu();
    }

    @Test
    void testGetMenuNameEditMenu() {
        // given
        when(_mockedService.getMenuNameEditMenu()).thenReturn(DUMMY_STRING);

        // when
        String result = MenuApi.getMenuNameEditMenu();

        // then
        assertThat(result).isEqualTo(DUMMY_STRING);
        verify(_mockedService).getMenuNameEditMenu();
    }

    @Test
    void testGetMenuNameAttributesMenu() {
        // given
        when(_mockedService.getMenuNameAttributesMenu()).thenReturn(DUMMY_STRING);

        // when
        String result = MenuApi.getMenuNameAttributesMenu();

        // then
        assertThat(result).isEqualTo(DUMMY_STRING);
        verify(_mockedService).getMenuNameAttributesMenu();
    }

    @Test
    void testGetMenuNameLayoutMenu() {
        // given
        when(_mockedService.getMenuNameLayoutMenu()).thenReturn(DUMMY_STRING);

        // when
        String result = MenuApi.getMenuNameLayoutMenu();

        // then
        assertThat(result).isEqualTo(DUMMY_STRING);
        verify(_mockedService).getMenuNameLayoutMenu();
    }

    @Test
    void testGetMenuNameToolsMenu() {
        // given
        when(_mockedService.getMenuNameToolsMenu()).thenReturn(DUMMY_STRING);

        // when
        String result = MenuApi.getMenuNameToolsMenu();

        // then
        assertThat(result).isEqualTo(DUMMY_STRING);
        verify(_mockedService).getMenuNameToolsMenu();
    }

    @Test
    void testGetMenuNamePaoseMenu() {
        // given
        when(_mockedService.getMenuNamePaoseMenu()).thenReturn(DUMMY_STRING);

        // when
        String result = MenuApi.getMenuNamePaoseMenu();

        // then
        assertThat(result).isEqualTo(DUMMY_STRING);
        verify(_mockedService).getMenuNamePaoseMenu();
    }

    @Test
    void testGetMenuNameHelpMenu() {
        // given
        when(_mockedService.getMenuNameHelpMenu()).thenReturn(DUMMY_STRING);

        // when
        String result = MenuApi.getMenuNameHelpMenu();

        // then
        assertThat(result).isEqualTo(DUMMY_STRING);
        verify(_mockedService).getMenuNameHelpMenu();
    }

    @Test
    void testGetWindowsCategoryNameTools() {
        // given
        when(_mockedService.getWindowsCategoryNameTools()).thenReturn(DUMMY_STRING);

        // when
        String result = MenuApi.getWindowsCategoryNameTools();

        // then
        assertThat(result).isEqualTo(DUMMY_STRING);
        verify(_mockedService).getWindowsCategoryNameTools();
    }

    @Test
    void testRegisterWindowsMenuDialog() {
        // when

        MenuApi.registerWindowsMenuDialog(DUMMY_STRING, DUMMY_DIALOG);

        // then
        verify(_mockedService).registerWindowsMenuDialog(DUMMY_STRING, DUMMY_DIALOG);

    }

    @Test
    void testUnregisterWindowsMenuDialog() {
        // when
        MenuApi.unregisterWindowsMenuDialog(DUMMY_DIALOG);

        // then
        verify(_mockedService).unregisterWindowsMenuDialog(DUMMY_DIALOG);

    }

    @Test
    void testRegisterWindowsMenuFrame() {
        // when
        MenuApi.registerWindowsMenuFrame(DUMMY_STRING, DUMMY_FRAME);

        // then
        verify(_mockedService).registerWindowsMenuFrame(DUMMY_STRING, DUMMY_FRAME);


    }

    @Test
    void testUnregisterWindowsMenuFrame() {
        // when
        MenuApi.unregisterWindowsMenuFrame(DUMMY_FRAME);

        // then
        verify(_mockedService).unregisterWindowsMenuFrame(DUMMY_FRAME);

    }

    @Test
    void testRegisterWindowsMenuItem() {
        // when
        MenuApi.registerWindowsMenuItem(DUMMY_JMENUITEM);

        // then
        verify(_mockedService).registerWindowsMenuItem(DUMMY_JMENUITEM);

    }

    @Test
    void testUnregisterWindowsMenuItem() {
        // when
        MenuApi.unregisterWindowsMenuItem(DUMMY_JMENUITEM);

        // then
        verify(_mockedService).unregisterWindowsMenuItem(DUMMY_JMENUITEM);
    }

}