package com.atlassian.bitbucket.installer.scripts;

import com.atlassian.bitbucket.installer.utils.InstallerUtils;
import com.atlassian.bitbucket.util.Version;
import com.install4j.api.context.InstallerContext;
import org.apache.commons.lang3.ArrayUtils;

import java.io.*;
import java.util.Optional;
import java.util.Properties;
import java.util.regex.Pattern;

import static com.atlassian.bitbucket.installer.InstallerConstants.KEY_APP_BITBUCKET_HOME;
import static com.atlassian.bitbucket.installer.InstallerConstants.VALUE_EXIT_ERROR_CODE;

/**
 * Confirm disable plugins screen refers to the screen that expects the user to acknowledge disabling of plugin while upgrading to 4.0.
 * @deprecated in 4.6 for removal in 5.0. This plugin check will no longer be performed.
 */
@Deprecated
public class ConfirmDisablePluginsScreen extends AbstractInstallerScript {

    private static final String USER_INSTALLED_PLUGINS_FOLDER = "shared/plugins/installed-plugins";
    private static final String LEGACY_USER_INSTALLED_PLUGINS_FOLDER = "plugins/installed-plugins";

    private static final Pattern PLUGINS_PATTERN = Pattern.compile(".*\\.(jar$|obr)$");
    private static final Version REBRAND_VERSION = new Version(4);

    private static final FilenameFilter FILENAME_FILTER = (file, fileName) -> PLUGINS_PATTERN.matcher(fileName).find();

    public ConfirmDisablePluginsScreen(InstallerContext context, InstallerUtils utils) {
        super(context, utils);
    }

    /**
     * Decides if we should show the "Confirm disable plugins" screen.
     * <p>
     * The screen is showed if the following criteria are satisfied.
     * 1) If its a upgrade
     * 2) If the previous stash version was less than 4.0
     * 3) If there is a *.jar or *.obr file in {STASH_HOME}/shared/plugins/installed-plugins or {STASH_HOME}/plugins/installed-plugins
     *
     * @return
     */
    public boolean shouldShowScreen() {
        getUtils().logInfo("Confirm disable plugin screen condition");
        if (getInstallationDetails().isNewInstall()) {
            return false;
        }

        File homeDirectory = new File((String) getContext().getVariable(KEY_APP_BITBUCKET_HOME));

        Optional<Version> version = getVersion(homeDirectory);
        return version.map(v -> {
            getUtils().logInfo("Previous Bitbucket version:" + v);
            //We are matching any version that's older than 4.x
            if (REBRAND_VERSION.compareTo(v) > 0) {
                File[] sharedPlugins = new File(homeDirectory, USER_INSTALLED_PLUGINS_FOLDER)
                        .listFiles(FILENAME_FILTER);
                File[] plugins = new File(homeDirectory, LEGACY_USER_INSTALLED_PLUGINS_FOLDER)
                        .listFiles(FILENAME_FILTER);

                if (ArrayUtils.isNotEmpty(plugins) || ArrayUtils.isNotEmpty(sharedPlugins)) {
                    getUtils().logInfo("User installed plugins exists");
                    return true;
                }
            }
            return false;
        }).orElse(false);
    }

    /**
     * This method validates if the user has acknowledged that the plugins will be disabled.
     *
     * In console mode if the user has not acknowledged that plugins will be disabled after the installation,
     * the installer will {@link InstallerContext#finish exit}
     *
     * @return {@code true} if the user has acknowledged that the plugins will be disabled. {@code false} otherwise.
     */
    public Boolean validateConfirmation() {
        boolean confirmed = getContext().getBooleanVariable("confirm.disable.plugins");
        if (confirmed) {
            return true;
        }

        getUtils().showErrorMessage(getContext().getMessage("configure.installation.confirm.disable.plugin.dialog"));

        if (getContext().isConsole()) {
            getContext().finish(VALUE_EXIT_ERROR_CODE);
        }

        return false;
    }

    private Optional<Version> getVersion(File homeDirectory) {
        File version = new File(homeDirectory, ".version");
        Properties properties = new Properties();
        if (version.exists()) {
            try (InputStream inputStream = new FileInputStream(version)) {
                properties.load(inputStream);

                return Optional.of(new Version(properties.getProperty("stash.home.build.version")));
            } catch (IOException e) {
                getUtils().logInfo(e.getMessage());
            }
        }
        return Optional.empty();
    }
}
