local addonName, ns = ...
_G.rOrbs = ns -- make global so other files see the same object
PlayerFrame:UnregisterAllEvents()
PlayerFrame:Hide()

-- Global helper to strip secret value taint (12.0+)
-- pcall(string.format) creates a NEW untainted string
function rOrbs_CleanNumber(v)
  if v == nil then return 0 end
  local ok, result = pcall(string.format, "%.10g", v)
  if ok then return tonumber(result) or 0 end
  return 0
end

-- all your init stuff
local LSM = LibStub("LibSharedMedia-3.0")
local mediaCallbacks = {}
local initCallbacks = {}
local configLoaded = false

LSM.RegisterCallback(ns, "LibSharedMedia_Registered", function(name, mediaType, key)
  if configLoaded then
    for _, callback in pairs(mediaCallbacks) do
      callback(name, mediaType, key)
    end
  end
end)

function ns.RegisterInit(nameOrFunc, maybeFunc)
    local name, func

    if type(nameOrFunc) == "function" then
        func = nameOrFunc
        local info = debug.getinfo(func, "Sl") -- get definition site
        local src = (type(info.short_src) == "string" and info.short_src) or "?"
        local line = tonumber(info.linedefined) or 0
        name = ("%s:%d"):format(src:match("AddOns/.+") or src, line)
    else
        name = tostring(nameOrFunc) -- force string in case someone passed a table
        func = maybeFunc
    end

    local wrapped = function()
        local ok, err = xpcall(func, debugstack)
        if not ok then
            error(("Init callback failed:\n%s"):format(err))
        end
    end

    table.insert(initCallbacks, { name = name, func = wrapped })
end


function ns:Init()
    local errors = {}

    for _, cb in ipairs(initCallbacks) do
        local ok, err = xpcall(cb.func, debugstack)
        if not ok then
            table.insert(errors, ("Init callback failed:\n%s"):format( err))
        end
    end

    -- After running everything, dump errors (if any) through Blizzard's handler
    if #errors > 0 then
        for _, msg in ipairs(errors) do
            geterrorhandler()(msg)
        end
    end

    wipe(initCallbacks)
end

function rOrbs:CheckClientVersion(version)
    if WOW_PROJECT_ID ~= version then return false
    else return true
    end
end

function ns:ListenForMediaChange(callback)
  table.insert(mediaCallbacks, callback)
end

-- DEBUG: Toggle individual target orb layers
-- /rorbsdebug 1..10 to toggle layers, /rorbsdebug to show status
-- /rorbsdebug info to print detailed layer info
SLASH_RORBSDEBUG1 = "/rorbsdebug"
SlashCmdList["RORBSDEBUG"] = function(msg)
  local orb = _G["rOrbsTargetHealthOrb"]
  if not orb then print("|cffff0000[rOrbs Debug]|r Target health orb not found") return end
  
  local layers = {
    { name = "bg",         obj = orb.bg,         desc = "1: Background (orb_back2)" },
    { name = "fill",       obj = orb.fill,       desc = "2: Fill StatusBar FRAME (the actual bar)", isFrame = true },
    { name = "fillTex",    obj = orb.fillTex,     desc = "3: Fill Texture object" },
    { name = "clipFrame",  obj = orb.clipFrame,   desc = "4: Clip Frame", isFrame = true },
    { name = "galaxies",   obj = orb.galaxies,    desc = "5: Galaxies (animated)", isTable = true },
    { name = "bubbles",    obj = orb.bubbles,     desc = "6: Bubbles (animated)", isTable = true },
    { name = "spark",      obj = orb.spark,        desc = "7: Spark" },
    { name = "lowHP",      obj = orb.lowHP,        desc = "8: Low HP Glow" },
    { name = "highlight",  obj = orb.highlight,    desc = "9: Gloss (orb_gloss)" },
    { name = "overlay",    obj = orb.overlay,      desc = "10: Overlay Frame (parent of gloss/skull/lowHP)", isFrame = true },
  }
  
  -- Store overlay ref for debug
  if not orb.overlay then
    -- Find overlay by child search
    for _, child in ipairs({orb:GetChildren()}) do
      local n = child:GetName()
      if n and n:find("Overlay") then
        orb.overlay = child
        layers[10].obj = child
        break
      end
    end
  end
  
  if msg == "info" then
    print("|cff00ff00[rOrbs Debug]|r === DETAILED INFO ===")
    -- Fill StatusBar info
    if orb.fill then
      local min, max = orb.fill:GetMinMaxValues()
      local val = orb.fill:GetValue()
      print(string.format("  Fill StatusBar: value=%.2f, min=%.2f, max=%.2f", val or 0, min or 0, max or 0))
      print(string.format("  Fill FrameLevel: %d, Strata: %s", orb.fill:GetFrameLevel(), orb.fill:GetFrameStrata()))
      local ft = orb.fill:GetStatusBarTexture()
      if ft then
        local r, g, b, a = ft:GetVertexColor()
        print(string.format("  FillTex VertexColor: r=%.2f g=%.2f b=%.2f a=%.2f", r or 0, g or 0, b or 0, a or 0))
        print(string.format("  FillTex DrawLayer: %s, Alpha: %.2f", ft:GetDrawLayer() or "?", ft:GetAlpha()))
        print(string.format("  FillTex Size: %.1f x %.1f", ft:GetWidth(), ft:GetHeight()))
      end
    end
    -- Highlight info
    if orb.highlight then
      local r, g, b, a = orb.highlight:GetVertexColor()
      print(string.format("  Gloss VertexColor: r=%.2f g=%.2f b=%.2f a=%.2f", r or 0, g or 0, b or 0, a or 0))
      local dl, sl = orb.highlight:GetDrawLayer()
      print(string.format("  Gloss DrawLayer: %s-%d, Alpha: %.2f, Blend: %s", dl or "?", sl or 0, orb.highlight:GetAlpha(), orb.highlight:GetBlendMode()))
    end
    -- Background info
    if orb.bg then
      local r, g, b, a = orb.bg:GetVertexColor()
      print(string.format("  BG VertexColor: r=%.2f g=%.2f b=%.2f a=%.2f", r or 0, g or 0, b or 0, a or 0))
      print(string.format("  BG Desaturated: %s", tostring(orb.bg:IsDesaturated())))
    end
    -- Orb frame info
    print(string.format("  Orb FrameLevel: %d", orb:GetFrameLevel()))
    -- List ALL textures on orb
    print("  --- All textures on orb button ---")
    for i, region in ipairs({orb:GetRegions()}) do
      if region.GetTexture then
        local tex = region:GetTexture()
        local texStr = tex and tostring(tex) or "nil"
        local texName = type(tex) == "string" and (tex:match("([^\\]+)$") or tex) or texStr
        local dl, sl = region:GetDrawLayer()
        local r, g, b, a = region:GetVertexColor()
        print(string.format("    [%d] tex=%s layer=%s-%d rgba=%.1f,%.1f,%.1f,%.1f vis=%s alpha=%.2f blend=%s", 
          i, texName, dl or "?", sl or 0, r, g, b, a, tostring(region:IsShown()), region:GetAlpha(), region:GetBlendMode()))
      end
    end
    -- List ALL child frames and THEIR textures
    print("  --- All child frames + their textures ---")
    local function dumpFrame(frame, indent)
      local n = frame:GetName() or "unnamed"
      print(string.format("%s[Frame] %s FL=%d vis=%s strata=%s type=%s", indent, n, frame:GetFrameLevel(), tostring(frame:IsShown()), frame:GetFrameStrata(), frame:GetObjectType()))
      for j, region in ipairs({frame:GetRegions()}) do
        if region.GetTexture then
          local tex = region:GetTexture()
          local texStr = tex and tostring(tex) or "nil"
          local texName = type(tex) == "string" and (tex:match("([^\\]+)$") or tex) or texStr
          local dl, sl = region:GetDrawLayer()
          local r, g, b, a = region:GetVertexColor()
          print(string.format("%s  [Tex %d] %s layer=%s-%d rgba=%.1f,%.1f,%.1f,%.1f vis=%s alpha=%.2f blend=%s", 
            indent, j, texName, dl or "?", sl or 0, r, g, b, a, tostring(region:IsShown()), region:GetAlpha(), region:GetBlendMode()))
        elseif region.GetText then
          print(string.format("%s  [Font %d] text='%s' vis=%s", indent, j, tostring(region:GetText()), tostring(region:IsShown())))
        end
      end
      for _, child in ipairs({frame:GetChildren()}) do
        dumpFrame(child, indent .. "    ")
      end
    end
    for _, child in ipairs({orb:GetChildren()}) do
      dumpFrame(child, "    ")
    end
    return
  end
  
  local num = tonumber(msg)
  if num and layers[num] then
    local layer = layers[num]
    if layer.isTable then
      local first = layer.obj and layer.obj[1]
      if first then
        local visible = first:IsShown()
        for _, t in pairs(layer.obj) do
          if visible then t:Hide() else t:Show() end
        end
        print("|cff00ff00[rOrbs Debug]|r", layer.desc, visible and "|cffff0000HIDDEN|r" or "|cff00ff00SHOWN|r")
      end
    elseif layer.isFrame then
      if layer.obj then
        local visible = layer.obj:IsShown()
        if visible then layer.obj:Hide() else layer.obj:Show() end
        print("|cff00ff00[rOrbs Debug]|r", layer.desc, visible and "|cffff0000HIDDEN|r" or "|cff00ff00SHOWN|r")
      else
        print("|cffff0000[rOrbs Debug]|r", layer.desc, "= NIL (not found)")
      end
    else
      if layer.obj then
        local visible = layer.obj:IsShown()
        if visible then layer.obj:Hide() else layer.obj:Show() end
        print("|cff00ff00[rOrbs Debug]|r", layer.desc, visible and "|cffff0000HIDDEN|r" or "|cff00ff00SHOWN|r")
      end
    end
  else
    print("|cff00ff00[rOrbs Debug]|r Target Health Orb Layers:")
    for i, layer in ipairs(layers) do
      local shown = "?"
      if layer.isTable then
        local first = layer.obj and layer.obj[1]
        shown = first and (first:IsShown() and "SHOWN" or "HIDDEN") or "nil"
      elseif layer.obj then
        shown = layer.obj:IsShown() and "SHOWN" or "HIDDEN"
      else
        shown = "nil"
      end
      print(string.format("  |cffffff00%d|r = %s [%s]", i, layer.desc, shown))
    end
    print("  |cffffff00info|r = Print detailed layer info")
    print("Usage: /rorbsdebug <1-10|info>")
  end
end
