
// region Loaded Servers

var _loadedServers = []
var selectedServer = null;

function getLoadedServer(options) {
    let servers = _loadedServers.filter(item => {

        for (let key in options) {
            if (item[key] !== options[key]) {
                return false
            }
        }

        return true;
    });

    return servers || [];
}

function getServerFromSnowflake(id) {
    server = getLoadedServer({id: id});
    if (!server.length) {
        throw new Error("No Server with that ID");
    }

    return server[0];
}

function addToLoadedServers(serverData, autoSelect=false) {
    _loadedServers.push(serverData);
    createSelectButton(serverData);

    if (autoSelect) {
        selectServer(serverData["id"]);
    }
}

function removeFromLoadedServers(id) {
    _loadedServers = _loadedServers.filter(item => item.id !== id);
    removeSelectButton(id)

    if (selectedServer.id === id) {
        selectedServer(null);
    }
}


// region Loaded Channels

var _loadedChannels = {};
async function loadedChannels(serverId) {
    if (!(serverId in _loadedChannels)) {
        await fetchChannels(serverId);
    }

    return _loadedChannels[serverId]
}

$(document).on("selectedServerChange", async function() {
    // Try load channels to determine if bot has permissions
    loadedChannels(selectedServer.id);
});

const fetchChannels = async serverId => {
    $(".sidebar .sidebar-item").prop("disabled", true);

    try {
        channels = await ajaxRequest(`/generate-channels?guild=${serverId}`, "GET");
        _loadedChannels[serverId] = channels;
        unspotItem(serverId);  // remove the spot because no errors occured
    }
    catch (error) {
        logError(error);
        unspotItem(serverId);

        switch (error?.status) {
            case 429:
                rateLimitedLoadingChannels(error.responseJSON.retry_after);
                break;

            case 403:
                notAuthorisedLoadingChannels(serverId);
                break;

            default:
                alert("unknown error loading channels");
                break;
        }
        
    }
    finally {
        $(".sidebar .sidebar-item").prop("disabled", false);
    }
}

const rateLimitedLoadingChannels = retryAfterSeconds => {
    createModal({
        title: "Failed to Fetch Server Channels",
        texts: [
            { content: "Discord is rate-limiting your request." },
            { content: `This happens when making requests too quickly. Retry after ${retryAfterSeconds} seconds to continue without issue.` }
        ],
        buttons: [
            {
                className: "btn-warning px-4",
                iconClass: "bi-arrow-return-right",
                closeModal: true
            }
        ]
    });
}

const notAuthorisedLoadingChannels = serverId => {
    // Mark the sidebar item as non-operational
    spotItem(serverId, "danger");

    const inviteBotToServer = () => {
        window.open(
            `https://discord.com/oauth2/authorize
?client_id=${discordClientId}
&permissions=2147534848
&scope=bot+applications.commands
&guild_id=${serverId}
&disable_guild_select=true`,
            "_blank"
        );
    }

    // Inform the user auth problem
    createModal({
        title: "Failed to Fetch Server Channels",
        texts: [
            { content: "The Discord Bot is unable to access this server's channels, certain features will not work." },
            { content: "Ensure the Bot is a member, and has the neccessary permissions to operate." }
        ],
        buttons: [
            {
                text: "Invite the Bot",
                className: "btn-primary me-3",
                iconClass: "bi-envelope-plus",
                closeModal: true,
                onClick: inviteBotToServer
            },
            {
                className: "btn-secondary",
                iconClass: "bi-arrow-return-right",
                closeModal: true
            }
        ]
    });
}


// region UI Buttons

function createSelectButton(serverData) {
    // server details
    const id = serverData["id"];
    const name = serverData["name"];
    const iconHash = serverData["icon_hash"];
    const isBotOperational = serverData["is_bot_operational"];

    let template = $($("#serverItemTemplate").html());
    const imageUrl = `https://cdn.discordapp.com/icons/${id}/${iconHash}.webp?size=80`;
    const altText = name.split(' ').map(word => word.charAt(0)).join('');  // initials of server name, used if iconUrl is 404

    template.find(".js-image").attr("src", imageUrl).attr("alt", altText);
    template.find(".js-name").text(name);
    template.find(".js-id").text(id);
    template.find(".sidebar-item").attr("data-id", id);

    // Show inoperational status, also, `isBotOperatioanl` can be null,
    // so we can't rely on it's truthy value.
    if (isBotOperational === false) {
        template.find(".sidebar-item").addClass("spot spot-danger");
    }

    // Bind the button for selecting this server
    template.find(".sidebar-item").off("click").on("click", function() {
        const myID = $(this).data("id");

        // only select if not already selected, otherwise hide sidebar on smaller screens (responsive)
        selectedServer?.id !== myID ? selectServer(myID) : setSidebarVisibility(false);
    });

    $("#serverList").prepend(template);
}

function removeSelectButton(id) {
    $(`#serverList .server-item[data-id=${id}]`).remove();
}

$("#backToSelectServer").on("click", function() {
    $("#noSelectedServer").show();
    $("#selectedServerContainer").hide();
    $("#serverList .server-item > .server-item-selector.active").removeClass("active");
    selectedServer = null;
});


// #region Server Selection

function selectServer(id) {
    let server = getServerFromSnowflake(id);
    if (!server) {
        $("#noSelectedServer").show();
        $("#selectedServerContainer").hide();
        selectServer = null;
        return;
    }

    // Change appearance of selected vs none-selected items
    $("#serverList .sidebar-item").removeClass("active");
    $(`#serverList .sidebar-item[data-id="${id}"]`).addClass("active");

    // Global variable
    selectedServer = server;

    // Update UI
    $("#noSelectedServer").hide();
    $("#selectedServerContainer").show().css("display", "flex");

    // Close sidebar on smaller screens
    setSidebarVisibility(false);

    // Announce change to any listeners
    $(document).trigger("selectedServerChange");
}


// #region Resolve Strings

function resolveServerStrings() {
    // Server icon
    $(".resolve-to-server-icon").attr(
        "src",
        `https://cdn.discordapp.com/icons/${selectedServer.id}/${selectedServer.icon_hash}.webp?size=80`
    ).attr("alt", selectedServer.name.split(' ').map(word => word.charAt(0)).join(''));

    // Server names
    $(".resolve-to-server-name").text(selectedServer.name);

    // Server Guild Ids
    $(".resolve-to-server-id").text(selectedServer.id);

    // Bot Invite links
    $(".resolve-to-invite-link").attr("href", `https://discord.com/oauth2/authorize
?client_id=${discordClientId}
&permissions=2147534848
&scope=bot+applications.commands
&guild_id=${selectedServer.id}
&disable_guild_select=true`);
}


// region Change Listener

$(document).on("selectedServerChange", async function() {
    resolveServerStrings();
    $("#serverJoinAlert").hide();
});


// region Load Servers

async function loadServers() {

    // Remove any previously loaded servers
    $(".sidebar .sidebar-item").closest("li").remove();

    // Show placeholder items & hide rate limit warning
    $(".sidebar .sidebar-loading").show();
    $(".sidebar .server-rate-limit").hide();

    try {
        const servers = await ajaxRequest("/generate-servers/", "GET"); 
        servers.forEach(server => addToLoadedServers(server, false));
    }
    catch (error) {
        switch (error?.status) {
            case 401:
                window.location.href = "/login";  // discord token has expired
                break;
            case 429:
                $(".sidebar .server-rate-limit").show();
                break;
            default:
                logError(error);
                break;
        }
    }
    finally {
        $(".sidebar .sidebar-loading").hide();
    }
}

// Retry load servers button
$(".sidebar .sidebar-retry-btn").on("click", loadServers);


// region Spot Icons

const unspotItem = id => {
    $(`.sidebar .sidebar-item[data-id="${id}"]`).removeClass(
        "spot spot-primary spot-secondary spot-success spot-info spot-warning spot-danger"
    );
}

const spotItem = (id, spotStyle) => {
    $(`.sidebar .sidebar-item[data-id="${id}"]`).addClass(`spot spot-${spotStyle}`);
}


// region View Other Users

$(".js-serverUsersBtn").on("click", () => {
    createModal({
        title: "Other Users",
        texts: [
            {content: "This feature has not yet been implemented."}
        ],
        buttons: [
            {
                className: "btn-secondary px-4",
                iconClass: "bi-arrow-return-right",
                closeModal: true
            }
        ]
    });
});


// region View Edit History

$(".js-serverHistoryBtn").on("click", () => {
    createModal({
        title: "Edit History",
        texts: [
            {content: "This feature has not yet been implemented."}
        ],
        buttons: [
            {
                className: "btn-secondary px-4",
                iconClass: "bi-arrow-return-right",
                closeModal: true
            }
        ]
    });
});


// region Delete Server Data

$(".js-eraseServerBtn").on("click", () => {
    const server = selectedServer;  // Store incase it changes
    const itemsToLose = arrayToHtmlList([
        "Subscriptions",
        "Filters",
        "Message Styles",
        "Tracked Content"
    ]).addClass("mb-3").prop("outerHTML");

    const eraseServerData = () => {
        alert("not implemented")
    }

    createModal({
        title: `Delete Data for ${server.name}?`,
        texts: [
            {content: "You will lose all data related to this server, including:"},
            {content: itemsToLose, html: true},
            {content: "Please reconsider this decision."}
        ],
        buttons: [
            {
                className: "btn-danger me-3",
                iconClass: "bi-trash3",
                closeModal: true,
                onClick: eraseServerData
            },
            {
                className: "btn-secondary px-4",
                iconClass: "bi-arrow-return-right",
                closeModal: true
            }
        ]
    })
});