package completer;

import java.util.ArrayList;
import java.util.List;

import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;

import de.renew.console.completer.PluginCompleter;
import de.renew.plugin.IPlugin;
import de.renew.plugin.PluginManager;

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

public class PluginCompleterTest {

    @Test
    void testComplete() {
        // given
        List<CharSequence> candidates = new ArrayList<>();
        try (MockedStatic<PluginManager> mockedPluginManager =
            Mockito.mockStatic(PluginManager.class)) {
            PluginManager mockPluginManager = mock(PluginManager.class);
            IPlugin mockPlugin = mock(IPlugin.class);
            //when
            when(mockPlugin.getName()).thenReturn("My Plugin");
            when(mockPluginManager.getPlugins()).thenReturn(List.of(mockPlugin));
            mockedPluginManager.when(PluginManager::getInstance).thenReturn(mockPluginManager);

            PluginCompleter completer = new PluginCompleter();
            int result = completer.complete("My", 2, candidates);

            // then
            assertThat(candidates).containsExactly("My_Plugin");
            assertThat(result).isEqualTo(0);
        }
    }

    @Test
    void testCompleteNoMatch() {
        // given
        List<CharSequence> candidates = new ArrayList<>();

        try (MockedStatic<PluginManager> mockedPluginManager =
            Mockito.mockStatic(PluginManager.class)) {
            PluginManager mockPluginManager = mock(PluginManager.class);
            IPlugin mockPlugin = mock(IPlugin.class);

            when(mockPlugin.getName()).thenReturn("My Plugin");
            when(mockPluginManager.getPlugins()).thenReturn(List.of(mockPlugin));
            mockedPluginManager.when(PluginManager::getInstance).thenReturn(mockPluginManager);

            PluginCompleter completer = new PluginCompleter();

            // when
            int result = completer.complete("Unknown", 7, candidates);

            // then
            assertThat(candidates).isEmpty();
            assertThat(result).isEqualTo(-1);
        }
    }

    @Test
    void testGetPluginNamesOnePlugin() {
        //given
        try (MockedStatic<PluginManager> mockedPluginManager =
            Mockito.mockStatic(PluginManager.class)) {
            PluginManager pluginManager = mock(PluginManager.class);
            mockedPluginManager.when(PluginManager::getInstance).thenReturn(pluginManager);

            IPlugin mockPlugin = mock(IPlugin.class);
            PluginCompleter completer = new PluginCompleter();
            //when
            when(pluginManager.getPlugins()).thenReturn(List.of(mockPlugin));
            when(mockPlugin.getName()).thenReturn("Console");

            ArrayList<String> pluginNames = completer.getPluginNames();
            //then
            assertThat(pluginNames).containsExactly("Console");
        }
    }

    @Test
    void testGetPluginNamesMultiplePlugins() {
        //given
        try (MockedStatic<PluginManager> mockedPluginManager =
            Mockito.mockStatic(PluginManager.class)) {
            PluginManager pluginManager = mock(PluginManager.class);
            mockedPluginManager.when(PluginManager::getInstance).thenReturn(pluginManager);

            IPlugin mockPlugin = mock(IPlugin.class);
            IPlugin mockPlugin2 = mock(IPlugin.class);
            IPlugin mockPlugin3 = mock(IPlugin.class);
            PluginCompleter completer = new PluginCompleter();
            //when
            when(pluginManager.getPlugins())
                .thenReturn(List.of(mockPlugin, mockPlugin2, mockPlugin3));
            when(mockPlugin.getName()).thenReturn("Console");
            when(mockPlugin2.getName()).thenReturn("UseCase Components");
            when(mockPlugin3.getName()).thenReturn("Mail Notification Net Components");

            ArrayList<String> pluginNames = completer.getPluginNames();
            //then
            assertThat(pluginNames).containsExactly(
                "Console", "UseCase_Components", "Mail_Notification_Net_Components");
        }
    }

    @Test
    void testGetPluginNamesNoPlugins() {
        //given
        try (MockedStatic<PluginManager> mockedPluginManager =
            Mockito.mockStatic(PluginManager.class)) {
            PluginManager pluginManager = mock(PluginManager.class);
            mockedPluginManager.when(PluginManager::getInstance).thenReturn(pluginManager);

            PluginCompleter completer = new PluginCompleter();
            //when

            ArrayList<String> pluginNames = completer.getPluginNames();
            //then
            assertThat(pluginNames).isEmpty();
        }
    }
}
