local API = rawget(_G, "LIDCOUNCIL_API")
local INTERNAL_API = type(API) == "table" and type(API.__internal) == "table" and API.__internal or nil
if type(INTERNAL_API) ~= "table" then
  error("LidCouncil missing internal API registry.")
end

INTERNAL_API.LIDCOUNCIL_CreatePanelsOverlayHelpers_Impl = function(deps)
  deps = type(deps) == "table" and deps or {}

  local DB = deps.DB
  local frames = deps.frames

  local PANEL_SPECIAL_STATS = {
    { key = "agility", label = "Agility" },
    { key = "stamina", label = "Stamina" },
    { key = "armor", label = "Armor" },
    { key = "speed", label = "Speed" },
    { key = "crit", label = "Critical Strike" },
    { key = "haste", label = "Haste" },
    { key = "mastery", label = "Mastery" },
    { key = "versatility", label = "Versatility" },
    { key = "leech", label = "Leech" },
    { key = "avoidance", label = "Avoidance" },
  }

  local function GetFPSColor(fps, cfg)
    local lowValue, highValue = 30, 60
    local lowColor = { 0.95, 0.24, 0.24, 1.00 }
    local midColor = { 1.00, 0.62, 0.16, 1.00 }
    local highColor = { 0.20, 0.90, 0.20, 1.00 }

    local special = cfg and cfg.specialContent
    local fpsCfg = special and special.fps
    if fpsCfg then
      lowValue = math.floor((tonumber(fpsCfg.lowValue) or lowValue) + 0.5)
      highValue = math.floor((tonumber(fpsCfg.highValue) or highValue) + 0.5)
      if highValue <= lowValue then highValue = lowValue + 1 end
      if type(fpsCfg.lowColor) == "table" then lowColor = fpsCfg.lowColor end
      if type(fpsCfg.midColor) == "table" then midColor = fpsCfg.midColor end
      if type(fpsCfg.highColor) == "table" then highColor = fpsCfg.highColor end
    end

    if fps > highValue then
      return highColor[1] or 0.20, highColor[2] or 0.90, highColor[3] or 0.20
    elseif fps >= lowValue then
      return midColor[1] or 1.00, midColor[2] or 0.62, midColor[3] or 0.16
    end
    return lowColor[1] or 0.95, lowColor[2] or 0.24, lowColor[3] or 0.24
  end

  local function GetPanelGraphSettings(cfg)
    local graph = cfg and cfg.diagnostic and cfg.diagnostic.graph or {}
    local updateInterval = tonumber(graph.updateInterval) or 0.1
    if updateInterval < 0.1 then updateInterval = 0.1 end
    if updateInterval > 2.0 then updateInterval = 2.0 end
    updateInterval = math.floor((updateInterval * 10) + 0.5) / 10
    local avgWindowSec = math.floor((tonumber(graph.avgWindowSec) or 10) + 0.5)
    if avgWindowSec < 5 then avgWindowSec = 5 end
    if avgWindowSec > 300 then avgWindowSec = 300 end
    local infoIntervalFPS = tonumber(graph.infoIntervalFPS) or 0.1
    if infoIntervalFPS < 0.1 then infoIntervalFPS = 0.1 end
    if infoIntervalFPS > 300 then infoIntervalFPS = 300 end
    infoIntervalFPS = math.floor((infoIntervalFPS * 10) + 0.5) / 10
    local infoIntervalAVG = tonumber(graph.infoIntervalAVG) or 10
    if infoIntervalAVG < 0.1 then infoIntervalAVG = 0.1 end
    if infoIntervalAVG > 300 then infoIntervalAVG = 300 end
    infoIntervalAVG = math.floor((infoIntervalAVG * 10) + 0.5) / 10
    local infoIntervalLOW = tonumber(graph.infoIntervalLOW) or 0.1
    if infoIntervalLOW < 0.1 then infoIntervalLOW = 0.1 end
    if infoIntervalLOW > 300 then infoIntervalLOW = 300 end
    infoIntervalLOW = math.floor((infoIntervalLOW * 10) + 0.5) / 10
    local style = (graph.style == "WAVE") and "WAVE" or "BARS"
    return {
      showFPS = (graph.showFPS ~= false),
      showAvg = graph.showAvg and true or false,
      showLow = graph.showLow and true or false,
      updateInterval = updateInterval,
      avgWindowSec = avgWindowSec,
      infoIntervalFPS = infoIntervalFPS,
      infoIntervalAVG = infoIntervalAVG,
      infoIntervalLOW = infoIntervalLOW,
      style = style,
    }
  end

  local function RGBToCode(r, g, b)
    local rr = math.floor((math.max(0, math.min(1, tonumber(r) or 1)) * 255) + 0.5)
    local gg = math.floor((math.max(0, math.min(1, tonumber(g) or 1)) * 255) + 0.5)
    local bb = math.floor((math.max(0, math.min(1, tonumber(b) or 1)) * 255) + 0.5)
    return string.format("|cff%02x%02x%02x", rr, gg, bb)
  end

  local function EnsurePanelOverlayWidgets(frame)
    if not frame or frame.__lid_overlayReady then return end

    local graph = CreateFrame("Frame", nil, frame, "BackdropTemplate")
    graph:SetPoint("TOPLEFT", 3, -3)
    graph:SetPoint("BOTTOMRIGHT", -3, 3)
    graph:SetBackdrop({
      bgFile = "Interface/Buttons/WHITE8x8",
      edgeFile = "Interface/Buttons/WHITE8x8",
      tile = false, edgeSize = 1,
      insets = { left = 1, right = 1, top = 1, bottom = 1 },
    })
    graph:SetBackdropColor(0.02, 0.02, 0.03, 0.25)
    graph:SetBackdropBorderColor(0, 0, 0, 0.45)
    graph:SetFrameLevel(frame:GetFrameLevel() + 1)
    graph:Hide()
    frame.__lid_diagGraph = graph
    frame.__lid_diagBars = {}
    frame.__lid_diagHistory = {}
    frame.__lid_diagElapsed = 0
    frame.__lid_diagInfoWidth = nil
    frame.__lid_diagInfoCache = nil

    local diagInfo = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    diagInfo:SetPoint("TOPRIGHT", -6, -8)
    diagInfo:SetJustifyH("RIGHT")
    diagInfo:SetWidth(92)
    diagInfo:SetText("")
    diagInfo:Hide()
    frame.__lid_diagInfoText = diagInfo

    local specialText = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    specialText:SetPoint("TOPRIGHT", -6, -24)
    specialText:SetJustifyH("RIGHT")
    specialText:SetWidth(math.max(20, (frame:GetWidth() or 40) - 12))
    specialText:SetText("")
    specialText:Hide()
    frame.__lid_specialText = specialText

    frame.__lid_overlayReady = true
  end

  local function DrawPanelFPSGraph(frame, fps, cfg, elapsedForInfo)
    local graph = frame.__lid_diagGraph
    local bars = frame.__lid_diagBars
    local history = frame.__lid_diagHistory
    if not graph or not bars or not history then return end

    local settings = GetPanelGraphSettings(cfg)
    local showInfo = settings.showFPS or settings.showAvg or settings.showLow
    local panelW = frame:GetWidth() or 120
    local rightInset = 3
    if showInfo then
      rightInset = math.max(58, math.floor(panelW * 0.34))
      if rightInset > 130 then rightInset = 130 end
    end
    if frame.__lid_diagInfoWidth ~= rightInset then
      graph:ClearAllPoints()
      graph:SetPoint("TOPLEFT", 3, -3)
      graph:SetPoint("BOTTOMRIGHT", -rightInset, 3)
      frame.__lid_diagInfoWidth = rightInset
    end

    history[#history + 1] = fps
    while #history > 240 do
      table.remove(history, 1)
    end

    local graphW = (graph:GetWidth() or 1) - 10
    local graphH = (graph:GetHeight() or 1) - 10
    if graphW < 1 then graphW = 1 end
    if graphH < 1 then graphH = 1 end

    local sampleCount
    if settings.style == "WAVE" then
      sampleCount = math.max(10, math.floor(graphW / 2))
    else
      sampleCount = math.max(12, math.floor(graphW / 4))
    end
    if sampleCount > 220 then sampleCount = 220 end
    if sampleCount < 2 then sampleCount = 2 end

    local srcOffset = #history - sampleCount
    local maxFPS = 60
    local sampleValues = {}
    local visibleLow = nil

    local function SampleAt(index)
      local v = history[index] or 0
      if settings.style == "WAVE" then
        local p1 = history[index - 1] or v
        local p2 = history[index - 2] or p1
        local n1 = history[index + 1] or v
        local n2 = history[index + 2] or n1
        return (p2 + (p1 * 2) + (v * 3) + (n1 * 2) + n2) / 9
      end
      return v
    end

    for i = 1, sampleCount do
      local src = SampleAt(srcOffset + i)
      sampleValues[i] = src
      if src > maxFPS then maxFPS = src end
      if (not visibleLow) or src < visibleLow then visibleLow = src end
    end
    if maxFPS < 1 then maxFPS = 1 end

    if settings.style == "WAVE" then
      local step = graphW / math.max(1, sampleCount - 1)
      for i = 1, sampleCount - 1 do
        if not bars[i] then
          local seg = graph:CreateTexture(nil, "ARTWORK")
          seg:SetTexture("Interface/Buttons/WHITE8x8")
          bars[i] = seg
        end
        local s1 = sampleValues[i] or 0
        local s2 = sampleValues[i + 1] or s1
        local y1 = 5 + math.floor((s1 / maxFPS) * graphH)
        local y2 = 5 + math.floor((s2 / maxFPS) * graphH)
        local x1 = 5 + math.floor((i - 1) * step)
        local x2 = 5 + math.floor(i * step)
        local bottom = math.min(y1, y2) - 1
        if bottom < 5 then bottom = 5 end
        local h = math.max(2, math.abs(y2 - y1) + 2)
        local w = math.max(1, (x2 - x1) + 1)
        local seg = bars[i]
        seg:ClearAllPoints()
        seg:SetPoint("BOTTOMLEFT", graph, "BOTTOMLEFT", x1, bottom)
        seg:SetSize(w, h)
        local r, g, b = GetFPSColor((s1 + s2) * 0.5, cfg)
        seg:SetVertexColor(r, g, b, 0.9)
        seg:Show()
      end
      for i = sampleCount, #bars do
        bars[i]:Hide()
      end
    else
      local barW = math.max(1, math.floor(graphW / sampleCount) - 1)
      for i = 1, sampleCount do
        if not bars[i] then
          local bar = graph:CreateTexture(nil, "ARTWORK")
          bar:SetTexture("Interface/Buttons/WHITE8x8")
          bars[i] = bar
        end
        local src = sampleValues[i] or 0
        local h = math.floor((src / maxFPS) * graphH)
        if h < 1 then h = 1 end
        local x = 5 + ((i - 1) * (barW + 1))
        local bar = bars[i]
        bar:ClearAllPoints()
        bar:SetPoint("BOTTOMLEFT", graph, "BOTTOMLEFT", x, 5)
        bar:SetSize(barW, h)
        local r, g, b = GetFPSColor(src, cfg)
        bar:SetVertexColor(r, g, b, 0.85)
        bar:Show()
      end
      for i = sampleCount + 1, #bars do
        bars[i]:Hide()
      end
    end

    local info = frame.__lid_diagInfoText
    if info then
      if showInfo then
        local fpsCfg = cfg and cfg.specialContent and cfg.specialContent.fps or {}
        if info.SetAlpha then
          info:SetAlpha(math.max(0, math.min(1, tonumber(fpsCfg.alpha) or 1)))
        end
        local fontKey = (fpsCfg.font and _G[fpsCfg.font]) and fpsCfg.font or "GameFontHighlightSmall"
        local fontSize = math.floor((tonumber(fpsCfg.size) or 14) + 0.5)
        if fontSize < 8 then fontSize = 8 end
        if fontSize > 40 then fontSize = 40 end
        local pW = frame:GetWidth() or 120
        local pH = frame:GetHeight() or 80
        local autoCap = math.floor((math.min(pW, pH) * 0.24) + 0.5)
        if autoCap < 8 then autoCap = 8 end
        if autoCap > 24 then autoCap = 24 end
        if fontSize > autoCap then fontSize = autoCap end
        local fontObj = _G[fontKey]
        local fontPath, _, fontFlags
        if fontObj and fontObj.GetFont then
          fontPath, _, fontFlags = fontObj:GetFont()
        end
        if not fontPath and GameFontHighlightSmall and GameFontHighlightSmall.GetFont then
          fontPath, _, fontFlags = GameFontHighlightSmall:GetFont()
        end
        if fontPath and info.SetFont then
          info:SetFont(fontPath, fontSize, fontFlags)
        end

        info:ClearAllPoints()
        info:SetPoint("TOPRIGHT", -6, -8)
        info:SetWidth(math.max(42, rightInset - 10))
        info:SetJustifyH("RIGHT")

        local stepElapsed = tonumber(elapsedForInfo) or settings.updateInterval
        if stepElapsed < 0.01 then stepElapsed = 0.01 end

        local windowSamples = math.max(1, math.floor((settings.avgWindowSec / math.max(0.1, settings.updateInterval)) + 0.5))
        local from = #history - windowSamples + 1
        if from < 1 then from = 1 end
        local avgSum, avgN = 0, 0
        for i = from, #history do
          avgSum = avgSum + (history[i] or 0)
          avgN = avgN + 1
        end
        if avgN < 1 then avgN = 1 end
        local avgFPS = avgSum / avgN
        local lowFPS = visibleLow or 0
        frame.__lid_diagInfoCache = frame.__lid_diagInfoCache or {
          fps = { elapsed = 0, value = fps },
          avg = { elapsed = 0, value = avgFPS },
          low = { elapsed = 0, value = lowFPS },
        }
        local cache = frame.__lid_diagInfoCache
        cache.fps.elapsed = (cache.fps.elapsed or 0) + stepElapsed
        cache.avg.elapsed = (cache.avg.elapsed or 0) + stepElapsed
        cache.low.elapsed = (cache.low.elapsed or 0) + stepElapsed
        if (not cache.fps.value) or cache.fps.elapsed >= settings.infoIntervalFPS then
          cache.fps.value = fps
          cache.fps.elapsed = 0
        end
        if (not cache.avg.value) or cache.avg.elapsed >= settings.infoIntervalAVG then
          cache.avg.value = avgFPS
          cache.avg.elapsed = 0
        end
        if (not cache.low.value) or cache.low.elapsed >= settings.infoIntervalLOW then
          cache.low.value = lowFPS
          cache.low.elapsed = 0
        end
        local lines = {}
        if settings.showFPS then
          local v = cache.fps.value or fps
          local r, g, b = GetFPSColor(v, cfg)
          lines[#lines + 1] = string.format("%sFPS %.1f|r", RGBToCode(r, g, b), v)
        end
        if settings.showAvg then
          local v = cache.avg.value or avgFPS
          local r, g, b = GetFPSColor(v, cfg)
          lines[#lines + 1] = string.format("%sAVG %.1f|r", RGBToCode(r, g, b), v)
        end
        if settings.showLow then
          local v = cache.low.value or lowFPS
          local r, g, b = GetFPSColor(v, cfg)
          lines[#lines + 1] = string.format("%sLOW %.1f|r", RGBToCode(r, g, b), v)
        end
        info:SetText(table.concat(lines, "\n"))
        info:Show()
      else
        info:SetText("")
        info:Hide()
        frame.__lid_diagInfoCache = nil
      end
    end
  end

  local function FormatMoneyText(copper)
    local gold = math.floor((copper or 0) / 10000)
    local silver = math.floor(((copper or 0) % 10000) / 100)
    local cop = math.floor((copper or 0) % 100)
    return string.format("%dg %ds %dc", gold, silver, cop)
  end

  local function BuildSpecialCache(fps, needs)
    local cache = {}
    needs = needs or {}

    if needs.fps then
      cache.fps = fps or 0
    end

    if needs.money then
      cache.money = (GetMoney and GetMoney()) or 0
    end

    if needs.stats then
      cache.stats = {}
      local _, agi = UnitStat("player", 2)
      local _, stam = UnitStat("player", 3)
      local _, armor = UnitArmor("player")
      local speedPct = 100
      if GetUnitSpeed then
        local curSpeed = GetUnitSpeed("player") or 0
        if curSpeed > 0 then
          speedPct = (curSpeed / 7) * 100
        else
          speedPct = 0
        end
      end
      local crit = (GetCritChance and GetCritChance()) or 0
      local haste = (GetHaste and GetHaste()) or 0
      local mastery = (GetMasteryEffect and GetMasteryEffect()) or 0
      local vers = 0
      if GetCombatRatingBonus and CR_VERSATILITY_DAMAGE_DONE then
        vers = GetCombatRatingBonus(CR_VERSATILITY_DAMAGE_DONE) or 0
      end
      local leech = (GetLifesteal and GetLifesteal()) or 0
      local avoidance = (GetAvoidance and GetAvoidance()) or 0

      cache.stats.agility = tostring(math.floor((agi or 0) + 0.5))
      cache.stats.stamina = tostring(math.floor((stam or 0) + 0.5))
      cache.stats.armor = tostring(math.floor((armor or 0) + 0.5))
      cache.stats.speed = string.format("%.0f%%", speedPct)
      cache.stats.crit = string.format("%.1f%%", crit)
      cache.stats.haste = string.format("%.1f%%", haste)
      cache.stats.mastery = string.format("%.1f%%", mastery)
      cache.stats.versatility = string.format("%.1f%%", vers)
      cache.stats.leech = string.format("%.1f%%", leech)
      cache.stats.avoidance = string.format("%.1f%%", avoidance)
    end

    return cache
  end

  local function ColorToHex(c, fallback)
    local src = c or fallback or { 1, 1, 1, 1 }
    local r = math.floor((math.max(0, math.min(1, tonumber(src[1]) or 1)) * 255) + 0.5)
    local g = math.floor((math.max(0, math.min(1, tonumber(src[2]) or 1)) * 255) + 0.5)
    local b = math.floor((math.max(0, math.min(1, tonumber(src[3]) or 1)) * 255) + 0.5)
    return string.format("|cff%02x%02x%02x", r, g, b)
  end

  local function ResolveSpecialFont(fontKey, size)
    local key = (fontKey and _G[fontKey]) and fontKey or "GameFontHighlightSmall"
    local obj = _G[key]
    local font, _, flags
    if obj and obj.GetFont then
      font, _, flags = obj:GetFont()
    end
    if not font and GameFontHighlightSmall and GameFontHighlightSmall.GetFont then
      font, _, flags = GameFontHighlightSmall:GetFont()
    end
    return font, math.max(8, math.floor((tonumber(size) or 14) + 0.5)), flags
  end

  local function ApplySpecialTextStyle(txt, fontKey, size, color)
    local font, fontSize, flags = ResolveSpecialFont(fontKey, size)
    if font and txt.SetFont then
      txt:SetFont(font, fontSize, flags)
    end
    local c = color or { 1, 1, 1, 1 }
    txt:SetTextColor(c[1] or 1, c[2] or 1, c[3] or 1, 1)
    if txt.SetAlpha then
      txt:SetAlpha(c[4] or 1)
    end
  end

  local function ResolveSpecialMode(cfg)
    local special = cfg and cfg.specialContent
    if not special then
      return "NONE", nil
    end

    local mode = special.mode
    if not mode then
      if cfg and cfg.diagnostic and cfg.diagnostic.fpsGraph then
        mode = "FPS_GRAPH"
      elseif special.showGold then
        mode = "GOLD"
      elseif special.showFPS then
        mode = "FPS"
      elseif special.showStats then
        mode = "STATS"
      elseif special.showCustomText then
        mode = "CUSTOM_TEXT"
      else
        mode = "NONE"
      end
    end
    return mode, special
  end

  local function ResetPanelOverlay(frame)
    if not frame or not frame.__lid_overlayReady then return end
    if frame.__lid_diagGraph then frame.__lid_diagGraph:Hide() end
    if frame.__lid_diagInfoText then
      frame.__lid_diagInfoText:SetText("")
      frame.__lid_diagInfoText:Hide()
    end
    if frame.__lid_specialText then
      frame.__lid_specialText:SetText("")
      frame.__lid_specialText:Hide()
    end
    frame.__lid_diagInfoCache = nil
    frame.__lid_diagElapsed = 0
  end

  local function PanelNeedsOverlayUpdates(cfg)
    if not cfg then return false end
    local mode = ResolveSpecialMode(cfg)
    if (cfg.diagnostic and cfg.diagnostic.fpsGraph) or (mode == "FPS_GRAPH") then
      return true
    end
    if mode == "GOLD" or mode == "FPS" or mode == "STATS" or mode == "CUSTOM_TEXT" then
      return true
    end
    return false
  end

  local function UpdatePanelSpecialContent(frame, cfg, fps, cache)
    local txt = frame.__lid_specialText
    if not txt then return end

    local special = cfg and cfg.specialContent
    if not special then
      txt:SetText("")
      txt:Hide()
      return
    end

    local mode = ResolveSpecialMode(cfg)

    local lines = {}
    if mode == "GOLD" then
      local goldCfg = special.gold or {}
      lines[1] = "Gold: " .. FormatMoneyText((cache and cache.money) or 0)
      ApplySpecialTextStyle(txt, goldCfg.font, goldCfg.size, goldCfg.color or { 1.00, 0.82, 0.00, 1.00 })
    elseif mode == "FPS" then
      local fpsCfg = special.fps or {}
      local fpsValue = (cache and cache.fps) or fps or 0
      local lowV = math.floor((tonumber(fpsCfg.lowValue) or 30) + 0.5)
      local highV = math.floor((tonumber(fpsCfg.highValue) or 60) + 0.5)
      if highV <= lowV then highV = lowV + 1 end
      local color = fpsCfg.midColor or { 1.00, 0.62, 0.16, 1.00 }
      if fpsValue < lowV then
        color = fpsCfg.lowColor or { 0.95, 0.24, 0.24, 1.00 }
      elseif fpsValue > highV then
        color = fpsCfg.highColor or { 0.20, 0.90, 0.20, 1.00 }
      end
      color = { color[1] or 1, color[2] or 1, color[3] or 1, tonumber(fpsCfg.alpha) or 1 }
      lines[1] = string.format("FPS: %.1f", fpsValue)
      ApplySpecialTextStyle(txt, fpsCfg.font, fpsCfg.size, color)
    elseif mode == "STATS" then
      local statsCfg = special.stats or {}
      local titleColors = special.statsTitleColors or {}
      local valueColors = special.statsValueColors or {}
      local selected = 0
      for _, def in ipairs(PANEL_SPECIAL_STATS) do
        if statsCfg[def.key] then
          local value = (cache and cache.stats and cache.stats[def.key]) or "-"
          local titleCode = ColorToHex(titleColors[def.key], { 0.84, 0.91, 1.00, 1.00 })
          local valueCode = ColorToHex(valueColors[def.key], { 1.00, 1.00, 1.00, 1.00 })
          lines[#lines + 1] = string.format("%s%s:|r %s%s|r", titleCode, def.label, valueCode, tostring(value))
          selected = selected + 1
        end
      end
      if selected == 0 then
        lines[1] = "Stats: none selected"
      end
      ApplySpecialTextStyle(txt, special.statsFont, special.statsSize, { 1, 1, 1, tonumber(special.statsAlpha) or 1 })
    elseif mode == "CUSTOM_TEXT" then
      local customCfg = special.customText or {}
      local customText = tostring(customCfg.text or "")
      if customText == "" then
        customText = "Custom Text"
      end
      lines[1] = customText
      ApplySpecialTextStyle(txt, customCfg.font, customCfg.size, customCfg.color or { 1, 1, 1, 1 })
    elseif mode == "FPS_GRAPH" then
      txt:SetText("")
      txt:Hide()
      return
    else
      txt:SetText("")
      txt:Hide()
      return
    end

    if #lines > 0 then
      txt:SetWidth(math.max(20, (frame:GetWidth() or 40) - 12))
      txt:SetText(table.concat(lines, "\n"))
      txt:Show()
    else
      txt:SetText("")
      txt:Hide()
    end
  end

  local panelOverlayUpdater = CreateFrame("Frame")
  panelOverlayUpdater:SetScript("OnUpdate", function(_, elapsed)
    panelOverlayUpdater.__lid_elapsed = (panelOverlayUpdater.__lid_elapsed or 0) + (elapsed or 0)
    if panelOverlayUpdater.__lid_elapsed < 0.1 then return end
    local tick = panelOverlayUpdater.__lid_elapsed
    panelOverlayUpdater.__lid_elapsed = 0

    local db = DB()
    local workItems = {}
    local needs = { fps = false, money = false, stats = false }

    for name, frame in pairs(frames) do
      if frame and frame:IsShown() then
        local cfg = db.panels[name]
        if cfg then
          local mode = ResolveSpecialMode(cfg)
          local showGraph = (cfg.diagnostic and cfg.diagnostic.fpsGraph) or (mode == "FPS_GRAPH")
          local showSpecial = (mode == "GOLD") or (mode == "FPS") or (mode == "STATS") or (mode == "CUSTOM_TEXT")
          if showGraph or showSpecial then
            workItems[#workItems + 1] = { frame = frame, cfg = cfg, mode = mode, showGraph = showGraph }
            if showGraph or mode == "FPS" then needs.fps = true end
            if mode == "GOLD" then needs.money = true end
            if mode == "STATS" then needs.stats = true end
          else
            ResetPanelOverlay(frame)
          end
        end
      else
        ResetPanelOverlay(frame)
      end
    end

    if #workItems == 0 then
      return
    end

    local fps = needs.fps and ((GetFramerate and GetFramerate()) or 0) or 0
    local cache = BuildSpecialCache(fps, needs)

    for _, item in ipairs(workItems) do
      local frame = item.frame
      local cfg = item.cfg
      EnsurePanelOverlayWidgets(frame)
      if item.showGraph then
        frame.__lid_diagGraph:Show()
        local graphSettings = GetPanelGraphSettings(cfg)
        frame.__lid_diagElapsed = (frame.__lid_diagElapsed or graphSettings.updateInterval) + tick
        if frame.__lid_diagElapsed >= graphSettings.updateInterval then
          local graphStep = frame.__lid_diagElapsed
          frame.__lid_diagElapsed = 0
          DrawPanelFPSGraph(frame, fps, cfg, graphStep)
        end
      else
        if frame.__lid_diagGraph then frame.__lid_diagGraph:Hide() end
        if frame.__lid_diagInfoText then
          frame.__lid_diagInfoText:SetText("")
          frame.__lid_diagInfoText:Hide()
        end
        frame.__lid_diagInfoCache = nil
        frame.__lid_diagElapsed = 0
      end
      UpdatePanelSpecialContent(frame, cfg, fps, cache)
    end
  end)
  panelOverlayUpdater:Hide()

  local function RefreshOverlayUpdaterState()
    local db = DB()
    local hasDemand = false

    for name, frame in pairs(frames) do
      if frame and frame:IsShown() then
        local cfg = db.panels[name]
        if PanelNeedsOverlayUpdates(cfg) then
          hasDemand = true
          break
        end
      else
        ResetPanelOverlay(frame)
      end
    end

    if hasDemand then
      if not panelOverlayUpdater:IsShown() then
        panelOverlayUpdater.__lid_elapsed = 0
        panelOverlayUpdater:Show()
      end
      return
    end

    panelOverlayUpdater.__lid_elapsed = 0
    panelOverlayUpdater:Hide()
    for _, frame in pairs(frames) do
      ResetPanelOverlay(frame)
    end
  end

  return {
    RefreshOverlayUpdaterState = RefreshOverlayUpdaterState,
  }
end
