/// <reference path="..\..\GSMyAdmin\WebRoot\Scripts\UI.js" />
/// <reference path="..\..\GSMyAdmin\WebRoot\Scripts\API.js" />
/// <reference path="..\..\GSMyAdmin\WebRoot\Scripts\Common.js" />

/* jshint undef: true, unused: false */
/* global API,UI,PluginHandler */
/* eslint eqeqeq: "off", curly: "error", require-atomic-updates: "off" */

this.plugin = {
    PreInit: function () {
        //Called prior to the plugins initialisation, before the tabs are loaded.
        //This method must not invoke any module/plugin specific API calls.
    },

    PostInit: function () {
        //The tabs have been loaded. You should wire up any event handlers here.
        UI.SetCustomConsoleMessageProcesssor(consoleLineProcessor);
        resetWizardHandlers();
    },

    AMPDataLoaded: function () {
        Features.FileManagerPlugin.RegisterContextMenuHandler("properties", "Import Configuration", importSettingsFile);
        Features.FileManagerPlugin.RegisterContextMenuHandler("jar", "Set as startup jar", updateJarFile);
        Features.FileManagerPlugin.RegisterControlledFile("server.properties", true, importSettingsFile, "Please import any changes so they are not overwritten by AMP.");
    },

    Reset: function () {

    },

    StartupFailure: handleFailure,

    SettingChanged: updateSettingVisibility
};

this.tabs = [];

this.stylesheet = "";    //Styles for tab-specific styles

async function updateJarFile(file) {
    await API.Core.RefreshSettingValueListAsync("MinecraftModule.Minecraft.ServerJAR");
    await sleepAsync(500); //Wait for the setting value list to update before setting the value, otherwise it may not find the new file in the list and fail to update.
    currentSettings["MinecraftModule.Minecraft.ServerJAR"].value(file.name);
    currentSettings["MinecraftModule.Minecraft.ServerJAR"].highlight();
}

async function importSettingsFile(file) {
    const data = await file.getContentsAsync();
    const regex = /^(\w.+)=(.*)$/gm;
    let match = regex.exec(data);
    let modifiedLines = [];
    let failedLines = [];
    let ignoredLines = [];
    let success = 0;

    //AMP manages these settings
    const skipSettings = ["server-ip", "server-port", "server-portv6"];

    const allTaggedSettings = Object.values(currentSettings).filter(s => s.node.startsWith("MinecraftModule") && s.tag != "" && !skipSettings.includes(s.tag));
    //Turn into an object where setting.tag is the key and setting.node is the value

    const tagToNodeMap = Object.fromEntries(
        allTaggedSettings
            .filter(s => typeof s.tag === "string" && s.tag.length > 0 && typeof s.node === "string")
            .map(s => [s.tag, s.node])
    );

    while (match != null) {
        const key = match[1], value = match[2];
        let compareValue = match[2];

        if (tagToNodeMap.hasOwnProperty(key)) {
            const node = tagToNodeMap[key];
            if (!currentSettings[node]) {
                failedLines.push(match[0]);
                match = regex.exec(data);
                continue;
            }

            if (currentSettings[node].settingType === "Enum") {
                const enumSetting = currentSettings[node].enumValues().find(v => v.name.toLocaleLowerCase() == value);
                if (enumSetting != null) { compareValue = enumSetting.value.toString(); }
            }

            if (currentSettings[node].value().toString() != compareValue) {
                modifiedLines.push(match[0]);
                currentSettings[node].setTypedValue(compareValue);
            }
            success++;
        }
        else {
            ignoredLines.push(match[0]);
        }

        match = regex.exec(data);
    }

    let infoMessage = "";
    infoMessage += (modifiedLines.length > 0) ? "The following settings had changes that were imported:\r\n\r\n" + modifiedLines.join("\r\n") + "\r\n\r\n" : "";
    infoMessage += (ignoredLines.length > 0) ? "The following lines were ignored:\r\n\r\n" + ignoredLines.join("\r\n") + "\r\n\r\n" : "";
    infoMessage += (failedLines.length > 0) ? "The following lines could not be imported:\r\n\r\n" + failedLines.join("\r\n") : "";   
    const title = (failedLines.length > 0) ? "Some settings were not imported." : "";

    UI.ShowModalAsync("Import Complete", `${success} modified entries were successfully imported. ${title}`, UI.Icons.Info, UI.OKActionOnly, null, null, infoMessage);
}

function updateSettingVisibility(node, value) {
    if (node === "MinecraftModule.Java.UseContainerMemoryLimits") {
        const useMemLimit = parseBool(value);
        setSettingDisabled("MinecraftModule.Java.MaxHeapSizeMB", useMemLimit);
        setSettingDisabled("MinecraftModule.Java.MinHeapSizeMB", useMemLimit);
    }
    else if (node === "MinecraftModule.Minecraft.ServerType") {
        const hideNodes = ["MinecraftModule.Minecraft.FTBModpack", "MinecraftModule.Minecraft.FTBModpackNew", "MinecraftModule.Minecraft.SpecificVersion", "MinecraftModule.Minecraft.SpecificForgeVersion", "MinecraftModule.Minecraft.SpecificNeoForgeVersion",
            "MinecraftModule.Minecraft.SpecificSpongeVersion", "MinecraftModule.Minecraft.SpecificSpigotVersion", "MinecraftModule.Minecraft.SpecificPaperVersion",
            "MinecraftModule.Minecraft.CustomStartupString", "MinecraftModule.Minecraft.CustomNormalizerRegex", "MinecraftModule.Minecraft.CustomNormalizerReplacement",
            "MinecraftModule.Minecraft.SpecificPurpurVersion", "MinecraftModule.Minecraft.FabricMCVersion", "MinecraftModule.Minecraft.FabricLoaderVersion", "MinecraftModule.Minecraft.FabricInstallerVersion",
            "MinecraftModule.Minecraft.SpecificVelocityVersion"];

        const showNodes = ["MinecraftModule.Game.SpawnProtectionRadius"];

        for (const element of hideNodes) {
            let n = element;
            setSettingVisibility(n, false);
        }

        for (const element of showNodes) {
            let node = element;
            setSettingVisibility(node, true);
        }

        switch (parseInt(value)) {
            case 10:
                setSettingVisibility("MinecraftModule.Minecraft.SpecificVersion", true);
                break;
            case 20:
            case 30:
                setSettingVisibility("MinecraftModule.Minecraft.SpecificSpigotVersion", true);
                break;
            case 31:
                setSettingVisibility("MinecraftModule.Minecraft.SpecificPaperVersion", true);
                break;
            case 32:
                setSettingVisibility("MinecraftModule.Minecraft.SpecificPurpurVersion", true);
                break;
            case 33:
                setSettingVisibility("MinecraftModule.Minecraft.FabricMCVersion", true);
                setSettingVisibility("MinecraftModule.Minecraft.FabricLoaderVersion", true);
                setSettingVisibility("MinecraftModule.Minecraft.FabricInstallerVersion", true);
                break;
            case 50:
                setSettingVisibility("MinecraftModule.Minecraft.SpecificForgeVersion", true);
                break;
            case 51:
                setSettingVisibility("MinecraftModule.Minecraft.SpecificNeoForgeVersion", true);
                break;
            case 120:
                setSettingVisibility("MinecraftModule.Minecraft.FTBModpack", true);
                break;
            case 122:
                setSettingVisibility("MinecraftModule.Minecraft.FTBModpackNew", true);
                break;
            case 60:
                setSettingVisibility("MinecraftModule.Minecraft.SpecificSpongeVersion", true);
                break;
            case 140: //Proxies
            case 150:
                setSettingVisibility("MinecraftModule.Minecraft.SpecificVelocityVersion", true);
                break;
            case 999:
                setSettingVisibility("MinecraftModule.Minecraft.CustomStartupString", true);
                setSettingVisibility("MinecraftModule.Minecraft.CustomNormalizerRegex", true);
                setSettingVisibility("MinecraftModule.Minecraft.CustomNormalizerReplacement", true);
                break;
        }
    }
}

const failureReasons = {
    EULA: "EULA"
};

async function handleFailure() {
    const result = await API.MinecraftModule.GetFailureReasonAsync();

    switch (result) {
        case failureReasons.EULA:
            {
                const acceptEULAResult = await UI.ShowModalAsync("Minecraft Server EULA",
                    {
                        text: "You must accept the Mojang EULA before you may run the Minecraft server.",
                        subtitle: "By clicking 'accept' you indicate that you have read and accept the terms of the linked agreement."
                    }, UI.Icons.Info,
                    [
                        new UI.ModalAction("Accept", true, "bgGreen"),
                        new UI.ModalAction("Decline", false, "bgRed")
                    ], "Minecraft End User Licence Agreement", "https://account.mojang.com/documents/minecraft_eula");

                if (acceptEULAResult === true) {
                    await API.MinecraftModule.AcceptEULAAsync();
                    await API.Core.StartAsync();
                }
                else {
                    await API.MinecraftModule.RejectEULAAsync();
                }
                break;
            }
        default:
            UI.ShowModalAsync("Unable to start server.", result == "" ? "No specific reason was given. See logs for further information." : result, UI.Icons.Exclamation, UI.OKActionOnly);
    }
}

function consoleLineProcessor(element) {
    //MB: If we end up with a 3rd or more expression, put them in an array and loop through them
    //instead of just adding more elseifs.
    const matchTextComponent = /TextComponent\{text='(.+?)',.+\}/;
    const matchGenericReason = /TranslatableComponent\{key='disconnect\.genericReason', args=\[(.+?)\],.+\}/;
    let text = $(element).text();

    if (text.match(matchTextComponent)) {
        text = text.replace(matchTextComponent, "$1");
        element.text(text);
        return true;
    }
    else if (text.match(matchGenericReason)) {
        text = text.replace(matchGenericReason, "$1");
        element.text(text);
        return true;
    }

    return false;
}