package de.renew.plugin.command;

import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.apache.commons.io.FileUtils;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

import de.renew.plugin.PluginManager;

import static de.renew.plugin.LoadHelper.addFinderForTestResources;
import static de.renew.plugin.LoadHelper.addTestModuleLayer;
import static de.renew.plugin.LoadHelper.assertModuleNotLoaded;
import static de.renew.plugin.LoadHelper.assertPluginNotLoaded;
import static de.renew.plugin.LoadHelper.getJar;
import static de.renew.plugin.LoadHelper.isModuleLoaded;
import static de.renew.plugin.LoadHelper.isPluginLoaded;
import static de.renew.plugin.command.CommandHelper.doExecuteSuccessfully;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class LoadCommandTest {
    @Test
    public void testGetDescription() {
        assertEquals(
            "Load a new plug-in. Type 'load -help' to get examples of usage.",
            new LoadCommand().getDescription());
    }

    @Test
    public void testGetArguments() {
        assertEquals("locationNames", new LoadCommand().getArguments());
    }

    @Disabled("Uses reflection on private fields that moved.")
    @Test
    public void testExecute() throws ClassNotFoundException, NoSuchFieldException,
        IllegalAccessException, URISyntaxException, IOException
    {
        // preconditions
        final Class<? extends LoadCommandTest> clazz = this.getClass();
        addFinderForTestResources(clazz);
        addTestModuleLayer(clazz);

        // URL Test
        final URL pluginPath1 = getJar(this.getClass(), "eins-main.jar");
        executeLoadTest("de.renew.eins", "TestPlugin eins", pluginPath1.toString());

        // File-Path Test
        final URL pluginPath2 = getJar(clazz, "zwei-main.jar");
        executeLoadTest("de.renew.zwei", "TestPlugin zwei", pluginPath2.getFile());

        // Simple FileName Test
        final Path target = Paths.get(PluginManager.getLoaderLocation().toURI()).resolve("plugins")
            .resolve("drei-main.jar");
        final Path source = Paths.get(getJar(this.getClass(), "drei-main.jar").toURI());
        FileUtils.copyFile(source.toFile(), target.toFile());
        executeLoadTest("de.renew.drei", "TestPlugin drei", "drei-main.jar");
        // TODO: why is it not possible to delete the file after loading?
    }

    @Disabled("Uses reflection on private fields that moved.")
    @Test
    public void testExecute2() throws NoSuchFieldException, ClassNotFoundException,
        IllegalAccessException, URISyntaxException, IOException
    {
        precheck("de.renew.multiplugin.eins", "TestPlugin multiplugin eins");
        precheck("de.renew.multiplugin.zwei", "TestPlugin multiplugin zwei");

        final Path target = Paths.get(PluginManager.getLoaderLocation().toURI()).resolve("plugins");
        final Path source1 = Paths.get(getJar(this.getClass(), "multiplugin-1-main.jar").toURI());
        final Path source2 = Paths.get(getJar(this.getClass(), "multiplugin-2-main.jar").toURI());
        FileUtils.copyFile(source1.toFile(), target.resolve("multiplugin-1-main.jar").toFile());
        FileUtils.copyFile(source2.toFile(), target.resolve("multiplugin-2-main.jar").toFile());

        // TODO: Impossible to read from console please check Ticket: Loader-97

        //        final String result = doExecuteSuccessfully(new LoadCommand(), "multiplugin*");

        //        postcheck("de.renew.multiplugin.eins", "TestPlugin multiplugin eins", result);
        //        postcheck("de.renew.multiplugin.zwei", "TestPlugin multiplugin zwei", result);

    }


    private static void executeLoadTest(
        final String moduleName, final String pluginName, final String... args)
        throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException
    {
        precheck(moduleName, pluginName);
        final String result = doExecuteSuccessfully(new LoadCommand(), args);
        postcheck(moduleName, pluginName, result);
    }

    private static void postcheck(
        final String moduleName, final String pluginName, final String result)
        throws NoSuchFieldException, ClassNotFoundException, IllegalAccessException
    {
        assertFalse(result.contains("No match found"), "No match found");
        assertFalse(result.contains("load failed"), "load failed");
        assertFalse(result.contains("already loaded"), "already loaded");
        assertTrue(isPluginLoaded(pluginName), "Plugin not loaded: " + pluginName);
        assertTrue(isModuleLoaded(moduleName), "Module not loaded: " + moduleName);
    }

    private static void precheck(final String moduleName, final String pluginName)
        throws NoSuchFieldException, ClassNotFoundException, IllegalAccessException
    {
        assertModuleNotLoaded(moduleName);
        assertPluginNotLoaded(pluginName);
    }
}
