require "MS/MS_IndicatorVisualConfig"

-- Centralized performance profile management for Modern Status indicator refresh intervals.
MS_PerformanceManager = MS_PerformanceManager or {}

local PM = MS_PerformanceManager

local VALID_MODES = {
    responsive = true,
    balanced = true,
    lightweight = true,
    custom = true,
}

local MODE_ORDER = { "responsive", "balanced", "lightweight", "custom" }

local MODE_LABEL_KEYS = {
    responsive = "IGUI_ModernStatus_PerformanceMode_Responsive",
    balanced = "IGUI_ModernStatus_PerformanceMode_Balanced",
    lightweight = "IGUI_ModernStatus_PerformanceMode_Lightweight",
    custom = "IGUI_ModernStatus_PerformanceMode_Custom",
}

local MODE_FALLBACK_LABELS = {
    responsive = "Responsive",
    balanced = "Balanced",
    lightweight = "Lightweight",
    custom = "Custom",
}

local MODE_SCALE = {
    responsive = 0.5,
    balanced = 1.0,
    lightweight = 2.0,
}

local MATRIX_BASE_INTERVAL_MS = 500

local function tr(key, fallback)
    if getTextOrNull then
        local translated = getTextOrNull(key)
        if translated and translated ~= key then
            return translated
        end
    end

    if getText then
        local ok, translated = pcall(getText, key)
        if ok and translated and translated ~= key then
            return translated
        end
    end

    return fallback
end

local function normalizeMode(mode)
    mode = tostring(mode or "balanced")
    if VALID_MODES[mode] then
        return mode
    end
    return "balanced"
end

local function clampIntervalMs(value)
    local interval = tonumber(value) or 1000
    if interval < 50 then interval = 50 end
    if interval > 10000 then interval = 10000 end
    return math.floor((interval + 25) / 50) * 50
end

local function getConfig(playerIndex)
    if not MSConfig then return nil end

    local config = MSConfig.loadConfig(playerIndex)
    if not config then
        config = MSConfig.createDefaultConfig(playerIndex)
    end

    config.globalSettings = config.globalSettings or MSConfig.getDefaultGlobalConfig()
    config.indicators = config.indicators or {}

    return config
end

local function clearConfigCaches()
    if not MSConfig then return end
    MSConfig.configCache = {}
    MSConfig.globalConfigCache = {}
end

local function updateRuntimeIndicators(playerIndex, mode)
    if mode == "custom" then return end
    if not StatusWidget or not StatusWidget.indicators then return end

    local indicators = StatusWidget.indicators[playerIndex]
    if not indicators then return end

    for _, indicator in pairs(indicators) do
        if indicator and indicator.getType then
            local interval = PM.getProfileUpdateIntervalMs(mode, indicator:getType())
            indicator.updateIntervalMs = interval
            if indicator.invalidateRenderSnapshot then
                indicator:invalidateRenderSnapshot()
            end
        end
    end
end

function PM.getModeOrder()
    return MODE_ORDER
end

function PM.isValidMode(mode)
    return VALID_MODES[tostring(mode or "")] == true
end

function PM.normalizeMode(mode)
    return normalizeMode(mode)
end

function PM.getModeLabel(mode)
    mode = normalizeMode(mode)
    return tr(MODE_LABEL_KEYS[mode], MODE_FALLBACK_LABELS[mode])
end

function PM.getCurrentMode(playerIndex)
    if not MSConfig then return "balanced" end

    local globalConfig = MSConfig.getGlobalConfig(playerIndex) or {}
    return normalizeMode(globalConfig.performanceMode)
end

function PM.getProfileUpdateIntervalMs(mode, indicatorType)
    mode = normalizeMode(mode)
    if mode == "custom" then
        mode = "balanced"
    end

    local baseInterval = 1000
    if MS_IndicatorVisualConfig and MS_IndicatorVisualConfig.getDefaultUpdateIntervalMs then
        baseInterval = MS_IndicatorVisualConfig.getDefaultUpdateIntervalMs(indicatorType)
    end

    return clampIntervalMs(baseInterval * (MODE_SCALE[mode] or 1.0))
end

function PM.getProfileMatrixIntervalMs(mode)
    mode = normalizeMode(mode)
    if mode == "custom" then
        mode = "balanced"
    end
    return clampIntervalMs(MATRIX_BASE_INTERVAL_MS * (MODE_SCALE[mode] or 1.0))
end

function PM.setMode(playerIndex, mode)
    if not MSConfig then return false end

    mode = normalizeMode(mode)
    local config = getConfig(playerIndex)
    if not config then return false end

    config.globalSettings.performanceMode = mode

    -- Non-custom modes are profiles: applying one rewrites stored indicator intervals at once.
    if mode ~= "custom" then
        for indicatorType, indicatorConfig in pairs(config.indicators or {}) do
            if type(indicatorConfig) == "table" then
                indicatorConfig.updateIntervalMs = PM.getProfileUpdateIntervalMs(mode, indicatorType)
            end
        end

        config.globalSettings.matrixSettings = config.globalSettings.matrixSettings or MSConfig.getDefaultMatrixConfig()
        config.globalSettings.matrixSettings.updateIntervalMs = PM.getProfileMatrixIntervalMs(mode)
    end

    clearConfigCaches()
    MSConfig.saveConfig(config, playerIndex)
    clearConfigCaches()

    updateRuntimeIndicators(playerIndex, mode)

    if MS_MatrixManager and MS_MatrixManager.refreshPlayer then
        MS_MatrixManager.refreshPlayer(playerIndex)
    end

    return true
end

function PM.markCustomMode(playerIndex)
    if not MSConfig then return false end

    local currentMode = PM.getCurrentMode(playerIndex)
    if currentMode == "custom" then
        return true
    end

    local config = getConfig(playerIndex)
    if not config then return false end

    config.globalSettings.performanceMode = "custom"
    clearConfigCaches()
    MSConfig.saveConfig(config, playerIndex)
    clearConfigCaches()
    return true
end

return MS_PerformanceManager
