package de.renew.plugin.command;


import java.io.PrintStream;

import org.junit.jupiter.api.Test;

import de.renew.plugin.IPlugin;
import de.renew.plugin.PluginManager;

import static de.renew.plugin.LoadHelper.getJar;
import static de.renew.plugin.LoadHelper.isPluginLoaded;
import static de.renew.plugin.command.CommandHelper.doExecuteSuccessfully;
import static de.renew.plugin.command.CommandHelper.doExecuteUnsuccessfully;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;


public class ListCommandTest {

    @Test
    public void testGetDescription() {

        assertEquals(
            new ListCommand().getDescription(),
            "lists all loaded plugins. Options: [-l| --long] for more information; "
                + "[-c| --comment] to show compile comments; "
                + "[-j|--jar] to show all JAR file locations;" + "[-o] to show ordered list.");
    }

    @Test
    public void testGetArguments() {
        assertEquals(
            new ListCommand().getArguments(), "(--ordered|--long|--jar|--help) (--ordered|--long)");
    }

    @Test
    public void testExecute() {

        //Test with null in Array
        String[] args1 = { null };
        PrintStream printStream1 = null;
        assertThrows(
            NullPointerException.class, () -> new ListCommand().execute(args1, printStream1));

        // check parameter -h --help
        final String help1 = doExecuteSuccessfully(new ListCommand(), "-h");
        assertTrue(
            help1.replaceAll("[\\r\\n]", "").contains(
                " -h,--help      Print this message."
                    + " -j,--jar       List locations of all jar files."
                    + " -l,--long      Display more information about every plugin."
                    + " -o,--ordered   Print ordered list.")); // this confirms that all commands remained the same for every command only on integration has to be confirmed

        // setup
        PluginManager.getInstance()
            .loadPlugin(getJar(this.getClass(), "ListCommand-eins-main.jar"));
        PluginManager.getInstance()
            .loadPlugin(getJar(this.getClass(), "ListCommand-zwei-main.jar"));

        assertTrue(isPluginLoaded("TestPlugin ListCommand1"));
        assertTrue(isPluginLoaded("TestPlugin ListCommand2"));

        // check if plugins are listed
        final String s = doExecuteSuccessfully(new ListCommand());
        assertTrue(s.contains("plugin TestPlugin ListCommand1"));
        assertTrue(s.contains("plugin TestPlugin ListCommand2"));

        // check if filter works appropriately
        final String s1 = doExecuteSuccessfully(new ListCommand(), "1");
        assertTrue(s1.contains("plugin TestPlugin ListCommand1"));
        assertFalse(s1.contains("plugin TestPlugin ListCommand2"));

        final String s2 = doExecuteSuccessfully(new ListCommand(), "TestPlugin");
        assertTrue(s2.contains("plugin TestPlugin ListCommand1"));
        assertTrue(s2.contains("plugin TestPlugin ListCommand2"));

        final String s3 =
            doExecuteSuccessfully(new ListCommand(), "xyzasdasdiufasdf a87zasd fasdf h");
        assertFalse(s3.contains("plugin TestPlugin ListCommand1"));
        assertFalse(s3.contains("plugin TestPlugin ListCommand2"));

        final String alias = doExecuteSuccessfully(new ListCommand(), "AliasForFilter");
        assertTrue(alias.contains("plugin TestPlugin ListCommand1"));
        assertFalse(alias.contains("plugin TestPlugin ListCommand2"));



        // test parameter -o --ordered
        final String s4 = doExecuteSuccessfully(new ListCommand(), "-o");
        assertTrue(
            s4.replaceAll("[\\r\\n]", "").trim()
                .contains("plugin TestPlugin ListCommand1" + "plugin TestPlugin ListCommand2"));

        final String s5 = doExecuteSuccessfully(new ListCommand(), "1", "-o");
        assertTrue(s5.replaceAll("[\\r\\n]", "").trim().contains("plugin TestPlugin ListCommand1"));
        assertFalse(
            s5.replaceAll("[\\r\\n]", "").trim().contains("plugin TestPlugin ListCommand2"));


        // test parameter -j --jar
        final CommandHelper.Result result =
            doExecuteUnsuccessfully(new ListCommand(), NullPointerException.class, "-j");
        assertTrue(
            result.output()
                .contains("resources/test/de.renew.plugin.command/ListCommand-eins-main.jar"));
        assertTrue(
            result.output()
                .contains("resources/test/de.renew.plugin.command/ListCommand-zwei-main.jar"));

        final CommandHelper.Result result2 =
            doExecuteUnsuccessfully(new ListCommand(), NullPointerException.class, "1", "-j");
        assertTrue(
            result2.output()
                .contains("resources/test/de.renew.plugin.command/ListCommand-eins-main.jar"));
        assertFalse(
            result2.output()
                .contains("resources/test/de.renew.plugin.command/ListCommand-zwei-main.jar"));



        // test parameter -l --long
        final String s6 = doExecuteSuccessfully(new ListCommand(), "-l");
        assertTrue(s6.contains("0.1"));
        assertTrue(s6.contains("0.5"));
        assertTrue(s6.contains("TestPlugin ListCommand1"));
        assertTrue(s6.contains("TestPlugin ListCommand2"));

        final String s7 = doExecuteSuccessfully(new ListCommand(), "1", "-l");
        assertTrue(s7.contains("0.1"));
        assertFalse(s7.contains("0.5"));
        assertTrue(s7.contains("TestPlugin ListCommand1"));
        assertFalse(s7.contains("TestPlugin ListCommand2"));

    }

    @Test
    public void testCompare() {
        ListCommand.PluginNameComparator comp = new ListCommand().new PluginNameComparator();

        final String stringEins = "eins";
        final String stringEins2 = "eins";
        final IPlugin iPlugin1 = mock(IPlugin.class);
        when(iPlugin1.getName()).thenReturn(stringEins);

        final String stringZwei = "zwei";
        final IPlugin iPlugin2 = mock(IPlugin.class);
        when(iPlugin2.getName()).thenReturn(stringZwei);

        final IPlugin iPlugin3 = mock(IPlugin.class);
        when(iPlugin3.getName()).thenReturn(stringEins2);


        assertEquals(stringEins.compareTo(stringZwei), comp.compare(iPlugin1, iPlugin2));
        assertEquals(stringEins.compareTo(stringEins2), comp.compare(iPlugin1, iPlugin3));
    }
}
