package org.jboss.installer.postinstall.task;

import com.google.auto.service.AutoService;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.SystemUtils;
import org.jboss.installer.core.InstallationData;
import org.jboss.installer.core.LoggerUtils;
import org.jboss.installer.postinstall.PostInstallTask;
import org.jboss.installer.postinstall.SimplePostInstallTask;
import org.jboss.installer.postinstall.TaskPrinter;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.concurrent.TimeUnit;

@AutoService(PostInstallTask.class)
public class JDBCDriverModuleTask implements SimplePostInstallTask {

    public static final String TASK_NAME = "post_install.task.jdbc_driver_configuration.name";
    private static final String FILE_SEPARATOR = SystemUtils.IS_OS_WINDOWS ?";":":";

    @Override
    public String getName() {
        return TASK_NAME;
    }

    @Override
    public String getSerializationName() {
        return "add-driver-module";
    }

    @Override
    public boolean applyToInstallation(InstallationData data, TaskPrinter printer) {
        printer.print("tasks.jdbc_module.started");
        JDBCDriverTask.Config config = data.getConfig(JDBCDriverTask.Config.class);
        assert config != null;

        final Path tempDir;
        try {
            tempDir = Files.createTempDirectory("eap-installer-tmp");
        } catch (IOException e) {
            LoggerUtils.taskLog.error("Unable to create temporary directory", e);
            printer.print("tasks.general.temp_fail");
            printer.print(e);
            return false;
        }

        try {
            final String cliScriptName = SystemUtils.IS_OS_WINDOWS?"jboss-cli.bat":"jboss-cli.sh";
            final List<String> jarList = config.hasResolvedJarList()?config.getResolvedJarList():config.getJarList();
            ProcessBuilder builder = new ProcessBuilder(data.getTargetFolder().resolve("bin").resolve(cliScriptName).toString(),
                    String.format("--command=module add --name=%s --resources=%s --dependencies=wildflyee.api",
                            config.getDatabaseDriver().getModuleName(), getResources(jarList, tempDir, printer)));
            builder.environment().put("NOPAUSE", "true");
            final Process process = builder.start();
            if (process.waitFor(30, TimeUnit.SECONDS)) {
                if (process.exitValue() == 0) {
                    printer.print("tasks.jdbc_module.finished");
                    return true;
                } else {
                    printer.print("tasks.jdbc_module.failed");
                    return false;
                }
            } else {
                throw new RuntimeException("Process timed out during execution");
            }
        } catch (IOException | InterruptedException e) {
            LoggerUtils.taskLog.error("Unable to create module", e);
            printer.print("tasks.jdbc_module.failed");
            printer.print(e);
            return false;
        } finally {
            if (tempDir != null) {
                FileUtils.deleteQuietly(tempDir.toFile());
            }
            // clean up temporary files
            if (config.getResolvedJarList() != null && !config.getResolvedJarList().isEmpty()) {
                for (int i = 0; i <config.getResolvedJarList().size(); i++) {
                    String resolvedJar = config.getResolvedJarList().get(0);
                    String originalJar = config.getJarList().get(0);
                    if (!resolvedJar.equals(originalJar)) {
                        FileUtils.deleteQuietly(Path.of(resolvedJar).toFile());
                    }
                }
            }
        }
    }

    private String getResources(List<String> jarList, Path tempDir, TaskPrinter printer) throws IOException {
        StringBuilder resourcePaths = new StringBuilder();
        for (String jarPath : jarList) {
            if (org.jboss.installer.core.FileUtils.isUrl(jarPath)) {
                printer.print("tasks.jdbc_module.downloading.started", jarPath);
                final URL jarUrl = new URL(jarPath);
                String fileName = jarUrl.getFile().substring(1);
                try (InputStream inputStream = jarUrl.openStream()) {
                    File jarFile = downloadJarFile(fileName, inputStream, tempDir);
                    resourcePaths.append(jarFile.getAbsolutePath()).append(FILE_SEPARATOR);
                    printer.print("tasks.jdbc_module.downloading.finished");
                } catch (IOException e) {
                    printer.print("tasks.jdbc_module.downloading.failed", jarPath);
                    throw e;
                }
            } else {
                resourcePaths.append(jarPath).append(FILE_SEPARATOR);
            }
        }
        resourcePaths.deleteCharAt(resourcePaths.lastIndexOf(FILE_SEPARATOR));
        return resourcePaths.toString();
    }

    private File downloadJarFile(String fileName, InputStream inputStream, Path tempDir) throws IOException {
        File jarFile = new File(tempDir.resolve(fileName).toString());
        FileUtils.copyInputStreamToFile(inputStream, jarFile);
        return jarFile;
    }
}
