/*
 * Copyright 2022 Red Hat, Inc. and/or its affiliates
 * and other contributors as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jboss.uninstaller;

import org.jboss.uninstaller.utils.UninstallerException;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Optional;
import java.util.ResourceBundle;

/**
 * Second stage of uninstaller. The {@code Uninstaller} should be started in a new process using resources extracted in
 * {@link UninstallerWrapper}. This allows {@code Uninstaller} to fully remove the EAP installation folder.
 *
 * If the command line argument {@code -console} or {@code -c} is provided, uninstaller runs in CLI mode, otherwise a
 * Swing confirmation screen is displayed.
 *
 * The location of the installation folder is read from a {@code uninstall.properties} file extracted from
 * {@code uninstaller.jar}.
 *
 * At the end of the run {@code Uninstaller} removes the temporary folder where the resources were extracted to.
 */
public class Uninstaller {
    private static final String UNINSTALLER_UNKNOWN_PATH = "uninstaller.uninstall.unknown_path";
    public static final String UNINSTALLER_ERROR = "uninstaller.error";

    public static final String UNINSTALL_PROPERTIES_FILE = "uninstall.properties";
    public static final ResourceBundle translations = ResourceBundle.getBundle("i18n/Message");
    // uninstaller doesn't have access to console, we need to use logFile
    private Path logFile;

    public static void main(String[] args) throws Exception {
        boolean console = false;
        String temp = null;
        for (String arg : args) {
            if (arg.contains("=")) {
                final String[] splitArg = arg.split("=");
                if ("-Dtemp.path".equals(splitArg[0])) {
                    temp = splitArg[1];
                }
            } else {
                if ("-console".equals(arg)) {
                    console = true;
                }
            }
        }

        final Optional<Path> tempPath = Optional.ofNullable(temp).map(Path::of);

        if (console) {
            final Uninstaller uninstaller = new Uninstaller();
            try {
                uninstaller.actionUninstall(tempPath);
            } catch (IOException|UninstallerException e) {
                uninstaller.debug(String.format(translations.getString(UNINSTALLER_ERROR), e.getMessage()), e);
            }
        } else {
            new UninstallerFrame(tempPath);
        }
    }

    public Uninstaller() {
        try {
            logFile = Files.createTempFile("eap-uninstaller", ".log");
        } catch (IOException e) {
            // ignore
        }
    }

    public void actionUninstall(Optional<Path> tempPath) throws IOException, UninstallerException {
        debug("[Uninstaller started]");
        Path installationPath = getInstallPath();
        debug("Located installation path: " + installationPath);

        debug("Starting to remove from: " + installationPath);
        delete(installationPath.toFile());
        debug("Done");


        if (tempPath.isPresent()) {
            debug("Starting to remove from: " + tempPath);
            delete(tempPath.get().toFile());
            debug("Done");
        }

        debug("[Uninstaller complete]");
    }

    public void debug(String msg) {
        if (logFile == null) {
            return;
        }

        try {
            Files.writeString(logFile, msg + System.lineSeparator(), StandardCharsets.UTF_8, StandardOpenOption.APPEND);
        } catch (IOException e) {
            // ignore
        }
    }

    public void debug(String msg, Exception cause) {
        if (logFile == null) {
            return;
        }

        debug(msg);
        try (PrintWriter pw = new PrintWriter(logFile.toFile())) {
            cause.printStackTrace(pw);
        } catch (IOException e) {
            // ignore
        }
    }

    private static void delete(File file) {
        if (file.isDirectory()) {
            for (File child : file.listFiles()) {
                delete(child);
            }
            if (file.list().length == 0) {
                if (!file.delete()) {
                    file.deleteOnExit();
                }
            }
        } else {
            if (!file.delete()) {
                file.deleteOnExit();
            }
        }
    }

    private static Path getInstallPath() throws UninstallerException {
        try (InputStream in = Uninstaller.class.getClassLoader().getResourceAsStream(UNINSTALL_PROPERTIES_FILE);
            final InputStreamReader in1 = new InputStreamReader(in, StandardCharsets.UTF_8);
            final BufferedReader reader = new BufferedReader(in1)
        ) {
            String installPath = reader.readLine();

            if (installPath == null || installPath.trim().equals("")) {
                throw new UninstallerException(Uninstaller.translations.getString(UNINSTALLER_UNKNOWN_PATH));
            }

            return Paths.get(installPath);
        } catch (IOException e) {
            throw new UninstallerException(Uninstaller.translations.getString(UNINSTALLER_UNKNOWN_PATH), e);
        }
    }
}
