// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.server.core.update.command;

import com.hypixel.hytale.server.core.command.system.arguments.system.Argument;
import com.hypixel.hytale.server.core.util.io.FileUtil;
import java.nio.file.StandardCopyOption;
import java.nio.file.CopyOption;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Files;
import java.nio.file.attribute.FileAttribute;
import com.hypixel.hytale.server.core.HytaleServerConfig;
import com.hypixel.hytale.server.core.ShutdownReason;
import java.io.IOException;
import com.hypixel.hytale.server.core.universe.Universe;
import joptsimple.OptionSpec;
import com.hypixel.hytale.server.core.Options;
import com.hypixel.hytale.server.core.HytaleServer;
import java.util.logging.Level;
import com.hypixel.hytale.server.core.update.UpdateService;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.command.system.CommandContext;
import com.hypixel.hytale.server.core.command.system.arguments.system.FlagArg;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.server.core.command.system.basecommands.CommandBase;

public class UpdateApplyCommand extends CommandBase
{
    private static final HytaleLogger LOGGER;
    private static final Message MSG_NO_STAGED;
    private static final Message MSG_BACKUP_FAILED;
    private final FlagArg confirmFlag;
    private static final String[] CONFIG_FILES;
    
    public UpdateApplyCommand() {
        super("apply", "server.commands.update.apply.desc");
        this.confirmFlag = this.withFlagArg("confirm", "server.commands.update.apply.confirm.desc");
    }
    
    @Override
    protected void executeSync(@Nonnull final CommandContext context) {
        final String stagedVersion = UpdateService.getStagedVersion();
        if (stagedVersion == null) {
            context.sendMessage(UpdateApplyCommand.MSG_NO_STAGED);
            return;
        }
        if (!((Argument<Arg, Boolean>)this.confirmFlag).get(context)) {
            context.sendMessage(Message.translation("server.commands.update.apply_confirm_required").param("version", stagedVersion));
            return;
        }
        if (!UpdateService.isValidUpdateLayout()) {
            context.sendMessage(Message.translation("server.commands.update.applying_no_launcher").param("version", stagedVersion));
            UpdateApplyCommand.LOGGER.at(Level.WARNING).log("No launcher script detected - update must be applied manually after shutdown");
        }
        else {
            context.sendMessage(Message.translation("server.commands.update.applying").param("version", stagedVersion));
        }
        final HytaleServerConfig.UpdateConfig config = HytaleServer.get().getConfig().getUpdateConfig();
        try {
            this.backupCurrentFiles();
            if (config.isRunBackupBeforeUpdate() && Options.getOptionSet().has(Options.BACKUP_DIRECTORY)) {
                final Universe universe = Universe.get();
                if (universe != null) {
                    UpdateApplyCommand.LOGGER.at(Level.INFO).log("Running server backup before update...");
                    universe.runBackup().join();
                    UpdateApplyCommand.LOGGER.at(Level.INFO).log("Server backup completed");
                }
            }
            else if (config.isRunBackupBeforeUpdate()) {
                UpdateApplyCommand.LOGGER.at(Level.WARNING).log("RunBackupBeforeUpdate is enabled but backups are not configured (no --backup-dir)");
            }
            if (config.isBackupConfigBeforeUpdate()) {
                this.backupConfigFiles();
            }
        }
        catch (final IOException e) {
            UpdateApplyCommand.LOGGER.at(Level.SEVERE).withCause(e).log("Failed to create backups before update");
            context.sendMessage(UpdateApplyCommand.MSG_BACKUP_FAILED);
            return;
        }
        HytaleServer.get().shutdownServer(ShutdownReason.UPDATE);
    }
    
    private void backupCurrentFiles() throws IOException {
        final Path backupDir = UpdateService.getBackupDir();
        final Path backupServerDir = backupDir.resolve("Server");
        if (!UpdateService.deleteBackupDir()) {
            throw new IOException("Failed to clear existing backup directory");
        }
        Files.createDirectories(backupServerDir, (FileAttribute<?>[])new FileAttribute[0]);
        final Path currentJar = Path.of("HytaleServer.jar", new String[0]);
        if (Files.exists(currentJar, new LinkOption[0])) {
            Files.copy(currentJar, backupServerDir.resolve("HytaleServer.jar"), StandardCopyOption.REPLACE_EXISTING);
        }
        final Path currentAot = Path.of("HytaleServer.aot", new String[0]);
        if (Files.exists(currentAot, new LinkOption[0])) {
            Files.copy(currentAot, backupServerDir.resolve("HytaleServer.aot"), StandardCopyOption.REPLACE_EXISTING);
        }
        final Path licensesDir = Path.of("Licenses", new String[0]);
        if (Files.exists(licensesDir, new LinkOption[0])) {
            FileUtil.copyDirectory(licensesDir, backupServerDir.resolve("Licenses"));
        }
        final Path assetsZip = Path.of("..", new String[0]).resolve("Assets.zip");
        if (Files.exists(assetsZip, new LinkOption[0])) {
            Files.copy(assetsZip, backupDir.resolve("Assets.zip"), StandardCopyOption.REPLACE_EXISTING);
        }
        UpdateApplyCommand.LOGGER.at(Level.INFO).log("Backed up current server files to %s", backupDir);
    }
    
    private void backupConfigFiles() throws IOException {
        final Path backupServerDir = UpdateService.getBackupDir().resolve("Server");
        Files.createDirectories(backupServerDir, (FileAttribute<?>[])new FileAttribute[0]);
        int count = 0;
        for (final String fileName : UpdateApplyCommand.CONFIG_FILES) {
            final Path file = Path.of(fileName, new String[0]);
            if (Files.exists(file, new LinkOption[0])) {
                Files.copy(file, backupServerDir.resolve(fileName), StandardCopyOption.REPLACE_EXISTING);
                ++count;
            }
        }
        UpdateApplyCommand.LOGGER.at(Level.INFO).log("Backed up %d config files to %s", count, backupServerDir);
    }
    
    static {
        LOGGER = HytaleLogger.forEnclosingClass();
        MSG_NO_STAGED = Message.translation("server.commands.update.no_staged");
        MSG_BACKUP_FAILED = Message.translation("server.commands.update.backup_failed");
        CONFIG_FILES = new String[] { "config.json", "permissions.json", "bans.json", "whitelist.json" };
    }
}
