require "MS/SettingPanel/MS_GlobalSettingsPanel"
require "MS/SettingPanel/MS_MatrixStylePanel"
require "MS/SettingPanel/MS_UnlinkedStylePanel"
require "MS/MS_PresetManager"
require "MS/MS_PerformanceManager"
require "MS/SettingPanel/MS_PresetsPanel"
require "MS/MS_GridManager"
require "MS/SettingPanel/MS_GridSizeDialog"
require "MS/SettingPanel/MS_IndicatorTooltipOpacityDialog"
require "MS/MS_IndicatorTooltipManager"
require "ISUI/ISPanel"
require "ISUI/ISContextMenu"

MS_GlobalControlPanel = ISPanel:derive("MS_GlobalControlPanel")

local function _addUnavailableOption(menu, text)
    local option = menu:addOption(text, nil, nil)
    option.notAvailable = true
    return option
end

local function _getToggleStateText(enabled)
    -- Return the visible state suffix used by toggle options in the context menu.
    return enabled and "On" or "Off"
end

local function _getStoredMoodlesState(panel)
    MS_GlobalControlPanel._moodlesState = MS_GlobalControlPanel._moodlesState or {}
    return MS_GlobalControlPanel._moodlesState
end

local function _getHideOriginalMoodlesConfigValue(config)
    -- Accept aliases written by older/dev builds, then normalize to the current key.
    if not config then return false end
    if config.hideOriginalMoodles ~= nil then
        return config.hideOriginalMoodles == true
    end
    if config.hideVanillaMoodles ~= nil then
        return config.hideVanillaMoodles == true
    end
    if config.hideOriginalMoodle ~= nil then
        return config.hideOriginalMoodle == true
    end
    return false
end

local function _rememberUIState(panel, key, ui)
    if not ui then return nil end

    local state = _getStoredMoodlesState(panel)
    state[key] = state[key] or {}
    local uiState = state[key][ui]
    if not uiState then
        uiState = {}
        state[key][ui] = uiState
        if ui.getX then uiState.x = ui:getX() end
        if ui.getY then uiState.y = ui:getY() end
        if ui.getWidth then uiState.width = ui:getWidth() end
        if ui.getHeight then uiState.height = ui:getHeight() end
        if ui.isVisible then uiState.visible = ui:isVisible() end
    end
    return uiState
end

local function _setUIHidden(panel, key, ui, shouldHide)
    if not ui then return end

    local uiState = _rememberUIState(panel, key, ui)
    if shouldHide then
        -- MoodlesUI in B42 can still be updated by the Java side or by moodle
        -- replacement mods, so use both visibility and an off-screen position.
        if ui.setVisible then ui:setVisible(false) end
        if ui.setX then ui:setX(-4096) end
        if ui.setY then ui:setY(-4096) end
    else
        local restoreVisible = true
        if uiState and uiState.visible ~= nil then
            restoreVisible = uiState.visible == true
        end
        if ui.setVisible then ui:setVisible(restoreVisible) end
        if uiState and uiState.width and ui.setWidth then ui:setWidth(uiState.width) end
        if uiState and uiState.height and ui.setHeight then ui:setHeight(uiState.height) end
        if uiState and uiState.x and ui.setX then ui:setX(uiState.x) end
        if uiState and uiState.y and ui.setY then ui:setY(uiState.y) end
    end
end

local function _collectVanillaMoodlesUI(panel)
    local seen = {}
    local result = {}

    local function add(ui)
        if ui and not seen[ui] then
            seen[ui] = true
            result[#result + 1] = ui
        end
    end

    if UIManager and UIManager.getMoodleUI then
        add(UIManager.getMoodleUI(panel.playerIndex or 0))
        -- Also scan all split-screen slots, because some MP/Host paths expose the
        -- current MoodlesUI through a slot that is not the saved config key.
        for i = 0, 3 do
            add(UIManager.getMoodleUI(i))
        end
    end

    if MoodlesUI and MoodlesUI.getInstance then
        add(MoodlesUI.getInstance())
    end

    if UIManager and UIManager.getUI then
        local uiList = UIManager.getUI()
        if uiList then
            for i = 0, uiList:size() - 1 do
                local ui = uiList:get(i)
                if ui and tostring(ui):find("MoodlesUI", 1, true) then
                    add(ui)
                end
            end
        end
    end

    return result
end

local function _applyVanillaMoodlesVisibility(panel, shouldHide)
    for _, moodlesUI in ipairs(_collectVanillaMoodlesUI(panel)) do
        _setUIHidden(panel, "vanilla", moodlesUI, shouldHide)
    end
end

local function _isMoodlesInLuaPresent()
    -- MoodlesInLua intentionally moves vanilla MoodlesUI off-screen every draw.
    -- When it is present, Modern Status must not restore vanilla moodles while
    -- only disabling its own hide option, or both tooltip stacks overlap.
    return ISMoodlesInLuaHandle ~= nil or ISMoodlesInLua ~= nil
end

local function _applyMoodlesInLuaVisibility(panel, shouldHide)
    if not ISMoodlesInLuaHandle then return end

    _setUIHidden(panel, "moodlesInLua", ISMoodlesInLuaHandle, shouldHide)
    if shouldHide then
        if ISMoodlesInLuaHandle.stop then
            ISMoodlesInLuaHandle:stop()
        end
    else
        if ISMoodlesInLuaHandle.start then
            ISMoodlesInLuaHandle:start()
        end
    end
end

local function _applyMoodleFrameworkVisibility(panel, shouldHide)
    if not MF then return end

    local seen = {}
    local function applyInstance(instance)
        if not instance or seen[instance] then return end
        seen[instance] = true
        _setUIHidden(panel, "moodleFramework", instance, shouldHide)
    end

    if MF.MoodlesStorage then
        for _, playerMoodles in pairs(MF.MoodlesStorage) do
            if type(playerMoodles) == "table" then
                for _, instance in pairs(playerMoodles) do
                    applyInstance(instance)
                end
            end
        end
    end

    if MF.ISMoodle and MF.ISMoodle.instances then
        for _, instance in ipairs(MF.ISMoodle.instances) do
            applyInstance(instance)
        end
    end
end

local function _applyKnownMoodleUIVisibility(panel, shouldHide, keepVanillaHidden)
    if not UIManager or not UIManager.getUI then return end

    local uiList = UIManager.getUI()
    if not uiList then return end

    for i = 0, uiList:size() - 1 do
        local ui = uiList:get(i)
        if ui then
            local text = tostring(ui)
            local looksLikeMoodleUI = false
            local isVanillaMoodlesUI = text and text:find("MoodlesUI", 1, true) ~= nil

            -- Lifestyle's LSMoodleManager creates anonymous ISUIElement tables
            -- with these methods, so tostring() alone is not enough to identify it.
            if ui.updateLSMoodles and ui.mouseOverMoodle and ui.level then
                looksLikeMoodleUI = true
            elseif text and text:find("Moodle", 1, true) and not text:find("ModernStatus", 1, true) then
                looksLikeMoodleUI = true
            end

            -- Vanilla MoodlesUI is handled only by _applyVanillaMoodlesVisibility().
            -- Do not process it again through the generic scanner: doing so can
            -- remember the already-hidden off-screen state under another key and
            -- then re-hide vanilla moodles immediately after they were restored.
            if looksLikeMoodleUI and not isVanillaMoodlesUI then
                _setUIHidden(panel, "knownMoodleUI", ui, shouldHide)
            end
        end
    end
end

-- ---------------------------------------------------------------------------------------- --
-- initialise
-- ---------------------------------------------------------------------------------------- --
function MS_GlobalControlPanel:initialise()
    ISPanel.initialise(self)
end

function MS_GlobalControlPanel:new(x, y, width, height, playerObj, playerIndex)
    local o = ISPanel:new(x, y, width, height)
    setmetatable(o, self)
    self.__index = self

    o.playerObj = playerObj
    o.playerIndex = playerIndex
    o.moveWithMouse = true
    o.locked = false
    o.moving = false

    o.controlTexture = getTexture("media/ui/ModernStatus/SettingPanel/SettingPanel_global.png")
    
    return o
end

-- ---------------------------------------------------------------------------------------- --
-- Context Menu
-- ---------------------------------------------------------------------------------------- --
function MS_GlobalControlPanel:addPresetMenus(context)
    -- Keep the Global Control Panel menu lightweight: the presets list is built inside its own panel.
    context:addOption(getText("IGUI_ModernStatus_Presets"), self, MS_GlobalControlPanel.openPresetsPanel)
end

function MS_GlobalControlPanel:onRightMouseDown(x, y)
    local context = ISContextMenu.get(self.playerIndex, getMouseX(), getMouseY())
    context:addOption(getText("IGUI_ModernStatus_OpenAllSettings"), self, MS_GlobalControlPanel.openAllSettings)

    context:addOption(getText("IGUI_ModernStatus_OpenMatrixSettings"), self, MS_GlobalControlPanel.openMatrixSettings)
    context:addOption(getText("IGUI_ModernStatus_OpenUnlinkedSettings"), self, MS_GlobalControlPanel.openUnlinkedSettings)
    self:addPresetMenus(context)
    
    local showHideText = getText("IGUI_ModernStatus_Show") .. "/" .. getText("IGUI_ModernStatus_Hide")
    local showHideOption = context:addOption(showHideText, nil)
    local showHideSubMenu = context:getNew(context)
    context:addSubMenu(showHideOption, showHideSubMenu)
    showHideSubMenu:addOption(getText("IGUI_ModernStatus_ShowAll"), self, MS_GlobalControlPanel.showAllIndicators)
    showHideSubMenu:addOption(getText("IGUI_ModernStatus_HideAll"), self, MS_GlobalControlPanel.hideAllIndicators)
    
    -- lock/Unlock
    local lockUnlockText = getText("IGUI_ModernStatus_Lock") .. "/" .. getText("IGUI_ModernStatus_Unlock")
    local lockUnlockOption = context:addOption(lockUnlockText, nil)
    local lockUnlockSubMenu = context:getNew(context)
    context:addSubMenu(lockUnlockOption, lockUnlockSubMenu)
    lockUnlockSubMenu:addOption(getText("IGUI_ModernStatus_LockAll"), self, MS_GlobalControlPanel.lockAllIndicators)
    lockUnlockSubMenu:addOption(getText("IGUI_ModernStatus_UnlockAll"), self, MS_GlobalControlPanel.unlockAllIndicators)

    -- grid
    local gridOption = context:addOption(getText("IGUI_ModernStatus_Grid"), nil)
    local gridSubMenu = context:getNew(context)
    context:addSubMenu(gridOption, gridSubMenu)

    -- Keep the explicit On/Off suffix and the vanilla checkmark so the current toggle state is clear at a glance.
    local forceToGridEnabled = MS_GridManager.isEnabled(self.playerIndex)
    local forceToGridText = getText("IGUI_ModernStatus_ForceToGrid") .. " (" .. _getToggleStateText(forceToGridEnabled) .. ")"
    local forceToGridOption = gridSubMenu:addOption(forceToGridText, self, MS_GlobalControlPanel.toggleForceToGrid)
    if gridSubMenu.setOptionChecked then
        gridSubMenu:setOptionChecked(forceToGridOption, forceToGridEnabled)
    end

    local gridSizeX, gridSizeY = MS_GridManager.getDisplaySize(self.playerIndex)
    local gridSizeText = getText("IGUI_ModernStatus_SetGridSize") .. " (" .. tostring(gridSizeX) .. ", " .. tostring(gridSizeY) .. ")"
    gridSubMenu:addOption(gridSizeText, self, MS_GlobalControlPanel.openGridSizeDialog)
    
    -- multiDrag
    local config = MSConfig.getGlobalConfig(self.playerIndex)
    local tooltipSettings = MS_IndicatorTooltipManager.getSettings(self.playerIndex)
    local multiDragText = getText("IGUI_ModernStatus_MultiDrag") .. " (" .. _getToggleStateText(config.multiDragMode == true) .. ")"
    local multiDragOption = context:addOption(multiDragText, self, MS_GlobalControlPanel.toggleMultiDragMode)
    if context.setOptionChecked then
        context:setOptionChecked(multiDragOption, config.multiDragMode == true)
    end

    local currentPerformanceMode = MS_PerformanceManager and MS_PerformanceManager.getCurrentMode and MS_PerformanceManager.getCurrentMode(self.playerIndex) or "balanced"
    local performanceText = getText("IGUI_ModernStatus_PerformanceMode")
    if MS_PerformanceManager and MS_PerformanceManager.getModeLabel then
        performanceText = performanceText .. " (" .. MS_PerformanceManager.getModeLabel(currentPerformanceMode) .. ")"
    end
    local performanceOption = context:addOption(performanceText, nil)
    local performanceSubMenu = context:getNew(context)
    context:addSubMenu(performanceOption, performanceSubMenu)
    if MS_PerformanceManager and MS_PerformanceManager.getModeOrder then
        for _, mode in ipairs(MS_PerformanceManager.getModeOrder()) do
            local modeOption = performanceSubMenu:addOption(MS_PerformanceManager.getModeLabel(mode), self, MS_GlobalControlPanel.setPerformanceMode, mode)
            if performanceSubMenu.setOptionChecked then
                performanceSubMenu:setOptionChecked(modeOption, currentPerformanceMode == mode)
            end
        end
    end

    local tooltipOption = context:addOption(getText("IGUI_ModernStatus_IndicatorTooltips"), nil)
    local tooltipSubMenu = context:getNew(context)
    context:addSubMenu(tooltipOption, tooltipSubMenu)

    local tooltipNameText = getText("IGUI_ModernStatus_TooltipName") .. " (" .. _getToggleStateText(tooltipSettings.showName ~= false) .. ")"
    local tooltipNameOption = tooltipSubMenu:addOption(tooltipNameText, self, MS_GlobalControlPanel.toggleTooltipName)
    if tooltipSubMenu.setOptionChecked then
        tooltipSubMenu:setOptionChecked(tooltipNameOption, tooltipSettings.showName ~= false)
    end

    local tooltipValueText = getText("IGUI_ModernStatus_TooltipValue") .. " (" .. _getToggleStateText(tooltipSettings.showValue ~= false) .. ")"
    local tooltipValueOption = tooltipSubMenu:addOption(tooltipValueText, self, MS_GlobalControlPanel.toggleTooltipValue)
    if tooltipSubMenu.setOptionChecked then
        tooltipSubMenu:setOptionChecked(tooltipValueOption, tooltipSettings.showValue ~= false)
    end

    local tooltipThresholdsText = getText("IGUI_ModernStatus_TooltipThresholds") .. " (" .. _getToggleStateText(tooltipSettings.showThresholds == true) .. ")"
    local tooltipThresholdsOption = tooltipSubMenu:addOption(tooltipThresholdsText, self, MS_GlobalControlPanel.toggleTooltipThresholds)
    if tooltipSubMenu.setOptionChecked then
        tooltipSubMenu:setOptionChecked(tooltipThresholdsOption, tooltipSettings.showThresholds == true)
    end

    local tooltipAssociatedMoodleText = getText("IGUI_ModernStatus_AssociatedMoodle") .. " (" .. _getToggleStateText(tooltipSettings.showAssociatedMoodle ~= false) .. ")"
    local tooltipAssociatedMoodleOption = tooltipSubMenu:addOption(tooltipAssociatedMoodleText, self, MS_GlobalControlPanel.toggleTooltipAssociatedMoodle)
    if tooltipSubMenu.setOptionChecked then
        tooltipSubMenu:setOptionChecked(tooltipAssociatedMoodleOption, tooltipSettings.showAssociatedMoodle ~= false)
    end

    local tooltipMoodleTitleText = getText("IGUI_ModernStatus_MoodleTitle") .. " (" .. _getToggleStateText(tooltipSettings.showMoodleTitle ~= false) .. ")"
    local tooltipMoodleTitleOption = tooltipSubMenu:addOption(tooltipMoodleTitleText, self, MS_GlobalControlPanel.toggleTooltipMoodleTitle)
    if tooltipSubMenu.setOptionChecked then
        tooltipSubMenu:setOptionChecked(tooltipMoodleTitleOption, tooltipSettings.showMoodleTitle ~= false)
    end

    local tooltipMoodleDescriptionText = getText("IGUI_ModernStatus_MoodleDescription") .. " (" .. _getToggleStateText(tooltipSettings.showMoodleDescription ~= false) .. ")"
    local tooltipMoodleDescriptionOption = tooltipSubMenu:addOption(tooltipMoodleDescriptionText, self, MS_GlobalControlPanel.toggleTooltipMoodleDescription)
    if tooltipSubMenu.setOptionChecked then
        tooltipSubMenu:setOptionChecked(tooltipMoodleDescriptionOption, tooltipSettings.showMoodleDescription ~= false)
    end

    local tooltipDetailedInfoText = getText("IGUI_ModernStatus_DetailedInfo") .. " (" .. _getToggleStateText(tooltipSettings.showDetailedInfo ~= false) .. ")"
    local tooltipDetailedInfoOption = tooltipSubMenu:addOption(tooltipDetailedInfoText, self, MS_GlobalControlPanel.toggleTooltipDetailedInfo)
    if tooltipSubMenu.setOptionChecked then
        tooltipSubMenu:setOptionChecked(tooltipDetailedInfoOption, tooltipSettings.showDetailedInfo ~= false)
    end

    local tooltipOpacityText = getText("IGUI_ModernStatus_SetOpacity") .. " (" .. tostring(MS_IndicatorTooltipManager.getOpacity(self.playerIndex)) .. ")"
    tooltipSubMenu:addOption(tooltipOpacityText, self, MS_GlobalControlPanel.openTooltipOpacityDialog)
    
    -- hide/show Moodle
    local hideOriginalMoodlesEnabled = _getHideOriginalMoodlesConfigValue(config)
    local hideOriginalMoodlesText = getText("IGUI_ModernStatus_HideVanillaMoodles") .. " (" .. _getToggleStateText(hideOriginalMoodlesEnabled) .. ")"
    local hideOriginalMoodlesOption = context:addOption(hideOriginalMoodlesText, self, MS_GlobalControlPanel.toggleHideOriginalMoodles)
    if context.setOptionChecked then
        context:setOptionChecked(hideOriginalMoodlesOption, hideOriginalMoodlesEnabled)
    end
    return true
end

function MS_GlobalControlPanel:openPresetsPanel()
    MS_PresetsPanel.openForPlayer(self.playerIndex)
end

function MS_GlobalControlPanel:saveCurrentPreset()
    MS_PresetManager.promptSavePreset(self.playerIndex)
end

function MS_GlobalControlPanel:loadBundledPreset(presetName)
    local preset = MS_PresetManager.getBundledPresetByName and MS_PresetManager.getBundledPresetByName(presetName) or MS_PresetManager.getBundledPresets()[presetName]
    MS_PresetManager.applyPreset(self.playerIndex, preset)
end

function MS_GlobalControlPanel:loadUserPreset(presetName)
    local preset = MS_PresetManager.getUserPresetByName and MS_PresetManager.getUserPresetByName(presetName) or MS_PresetManager.getUserPresets()[presetName]
    MS_PresetManager.applyPreset(self.playerIndex, preset)
end

function MS_GlobalControlPanel:deletePreset(presetName)
    MS_PresetManager.deleteUserPreset(presetName)
end

-- ---------------------------------------------------------------------------------------- --
-- Gobal Control
-- ---------------------------------------------------------------------------------------- --
function MS_GlobalControlPanel:openUnlinkedSettings()
    MS_UnlinkedStylePanel.openForPlayer(self.playerIndex)
end

function MS_GlobalControlPanel:openMatrixSettings()
    MS_MatrixStylePanel.openForPlayer(self.playerIndex)
end

function MS_GlobalControlPanel:openAllSettings()
    if not MS_AllIndicatorsPanel then
        require "MS/SettingPanel/MS_AllIndicatorsPanel"
    end

    MS_AllIndicatorsPanel.openForPlayer(self.playerIndex)
end

function MS_GlobalControlPanel:showAllIndicators()
    local indicators = StatusWidget.indicators[self.playerIndex]
    if not indicators then return end
    
    for _, indicator in pairs(indicators) do
        indicator.hidden = false
        indicator:setVisible(true)
        
        MSConfig.updateIndicatorConfig(
            indicator.playerIndex,
            indicator:getType(),
            "hidden",
            false
        )
    end

    if MS_MatrixManager and MS_MatrixManager.applyMatrixLayout then
        MS_MatrixManager.applyMatrixLayout(self.playerIndex)
    end
end

function MS_GlobalControlPanel:hideAllIndicators()
    local indicators = StatusWidget.indicators[self.playerIndex]
    if not indicators then return end
    
    for _, indicator in pairs(indicators) do
        indicator.hidden = true
        indicator:setVisible(false)
        
        MSConfig.updateIndicatorConfig(
            indicator.playerIndex,
            indicator:getType(),
            "hidden",
            true
        )
    end

    if MS_MatrixManager and MS_MatrixManager.applyMatrixLayout then
        MS_MatrixManager.applyMatrixLayout(self.playerIndex)
    end
end

function MS_GlobalControlPanel:lockAllIndicators()
    local indicators = StatusWidget.indicators[self.playerIndex]
    if not indicators then return end
    
    for _, indicator in pairs(indicators) do
        indicator.locked = true
        indicator.moveWithMouse = false
        
        MSConfig.updateIndicatorConfig(
            indicator.playerIndex,
            indicator:getType(),
            "locked",
            true
        )
    end
end

function MS_GlobalControlPanel:unlockAllIndicators()
    local indicators = StatusWidget.indicators[self.playerIndex]
    if not indicators then return end
    
    for _, indicator in pairs(indicators) do
        indicator.locked = false
        indicator.moveWithMouse = true
        
        MSConfig.updateIndicatorConfig(
            indicator.playerIndex,
            indicator:getType(),
            "locked",
            false
        )
    end
end

function MS_GlobalControlPanel:toggleMultiDragMode()
    local config = MSConfig.getGlobalConfig(self.playerIndex)
    local newMode = not config.multiDragMode
    
    MSConfig.updateGlobalConfig(
        self.playerIndex,
        "multiDragMode",
        newMode
    )
end

function MS_GlobalControlPanel:setPerformanceMode(mode)
    if MS_PerformanceManager and MS_PerformanceManager.setMode then
        MS_PerformanceManager.setMode(self.playerIndex, mode)
    end
end

function MS_GlobalControlPanel:toggleForceToGrid()
    MS_GridManager.setEnabled(self.playerIndex, not MS_GridManager.isEnabled(self.playerIndex))
end

function MS_GlobalControlPanel:openGridSizeDialog()
    local dialogX = math.floor(self:getAbsoluteX() + self:getWidth() + 10)
    local dialogY = math.floor(self:getAbsoluteY())
    MS_GridSizeDialog.openForPlayer(self.playerIndex, dialogX, dialogY)
end

function MS_GlobalControlPanel:toggleTooltipName()
    local settings = MS_IndicatorTooltipManager.getSettings(self.playerIndex)
    MS_IndicatorTooltipManager.updateSetting(self.playerIndex, "showName", settings.showName == false)
end

function MS_GlobalControlPanel:toggleTooltipValue()
    local settings = MS_IndicatorTooltipManager.getSettings(self.playerIndex)
    MS_IndicatorTooltipManager.updateSetting(self.playerIndex, "showValue", settings.showValue == false)
end

function MS_GlobalControlPanel:toggleTooltipThresholds()
    local settings = MS_IndicatorTooltipManager.getSettings(self.playerIndex)
    MS_IndicatorTooltipManager.updateSetting(self.playerIndex, "showThresholds", settings.showThresholds ~= true)
end

function MS_GlobalControlPanel:toggleTooltipAssociatedMoodle()
    local settings = MS_IndicatorTooltipManager.getSettings(self.playerIndex)
    MS_IndicatorTooltipManager.updateSetting(self.playerIndex, "showAssociatedMoodle", settings.showAssociatedMoodle == false)
end

function MS_GlobalControlPanel:toggleTooltipMoodleTitle()
    local settings = MS_IndicatorTooltipManager.getSettings(self.playerIndex)
    MS_IndicatorTooltipManager.updateSetting(self.playerIndex, "showMoodleTitle", settings.showMoodleTitle == false)
end

function MS_GlobalControlPanel:toggleTooltipMoodleDescription()
    local settings = MS_IndicatorTooltipManager.getSettings(self.playerIndex)
    MS_IndicatorTooltipManager.updateSetting(self.playerIndex, "showMoodleDescription", settings.showMoodleDescription == false)
end

function MS_GlobalControlPanel:toggleTooltipDetailedInfo()
    local settings = MS_IndicatorTooltipManager.getSettings(self.playerIndex)
    MS_IndicatorTooltipManager.updateSetting(self.playerIndex, "showDetailedInfo", settings.showDetailedInfo == false)
end

function MS_GlobalControlPanel:openTooltipOpacityDialog()
    local dialogX = math.floor(self:getAbsoluteX() + self:getWidth() + 10)
    local dialogY = math.floor(self:getAbsoluteY())
    MS_IndicatorTooltipOpacityDialog.openForPlayer(self.playerIndex, dialogX, dialogY)
end

function MS_GlobalControlPanel:toggleHideOriginalMoodles()
    local config = MSConfig.getGlobalConfig(self.playerIndex)
    local newValue = not _getHideOriginalMoodlesConfigValue(config)
    
    MSConfig.updateGlobalConfig(
        self.playerIndex,
        "hideOriginalMoodles",
        newValue
    )
    MSConfig.updateGlobalConfig(
        self.playerIndex,
        "hideVanillaMoodles",
        newValue
    )
    
    self:applyHideOriginalMoodles(newValue)
    if StatusWidget and StatusWidget.pendingMoodleVisibility then
        StatusWidget.pendingMoodleVisibility[self.playerIndex] = { control = self, shouldHide = newValue, ticks = 180 }
    end
end

function MS_GlobalControlPanel:applyHideOriginalMoodles(shouldHide)
    local keepVanillaHidden = shouldHide ~= true and _isMoodlesInLuaPresent()

    -- MoodlesInLua replaces vanilla moodles by keeping MoodlesUI off-screen even
    -- when Modern Status is not hiding moodles. Do not undo that external hide.
    if shouldHide or not keepVanillaHidden then
        _applyVanillaMoodlesVisibility(self, shouldHide)
    end

    _applyMoodlesInLuaVisibility(self, shouldHide)
    _applyMoodleFrameworkVisibility(self, shouldHide)
    _applyKnownMoodleUIVisibility(self, shouldHide, keepVanillaHidden)
end

-- ---------------------------------------------------------------------------------------- --
-- Mouse Function
-- ---------------------------------------------------------------------------------------- --
function MS_GlobalControlPanel:onMouseDown(x, y)
    if self.locked then return false end
    
    self.dragStartX = x
    self.dragStartY = y
    self.moving = true
    self:setCapture(true)
    return true
end

function MS_GlobalControlPanel:onMouseUp(x, y)
    if self.moving then
        self.moving = false
        self:setCapture(false)
        
        MSConfig.updateGlobalConfig(
            self.playerIndex,
            "controlPosition",
            {x = self:getX(), y = self:getY()}
        )
    end
    return true
end

function MS_GlobalControlPanel:onMouseMove(dx, dy)
    if self.moving then
        self:setX(self.x + dx)
        self:setY(self.y + dy)
    end
    return true
end

function MS_GlobalControlPanel:onMouseMoveOutside(dx, dy)
    if self.moving then
        self:setX(self.x + dx)
        self:setY(self.y + dy)
    end
    return true
end

function MS_GlobalControlPanel:prerender()
    self:drawTextureScaled(self.controlTexture, 0, 0, self.width, self.height, 1, 1, 1, 1)
end

-- Modern Status beta 9: open the new global settings panel from the blue cog instead of rebuilding the old context menu.
local _oldMS_GlobalControlPanelOnRightMouseDown = MS_GlobalControlPanel.onRightMouseDown
function MS_GlobalControlPanel:onRightMouseDown(x, y)
    if MS_GlobalSettingsPanel and MS_GlobalSettingsPanel.openForPlayer then
        local panelX = math.floor((self.getAbsoluteX and self:getAbsoluteX() or self:getX()) + self:getWidth() + 8)
        local panelY = math.floor(self.getAbsoluteY and self:getAbsoluteY() or self:getY())
        MS_GlobalSettingsPanel.openForPlayer(self.playerIndex or 0, panelX, panelY)
        return true
    end
    if _oldMS_GlobalControlPanelOnRightMouseDown then
        return _oldMS_GlobalControlPanelOnRightMouseDown(self, x, y)
    end
    return true
end
