  -- rOrbs: click-cast on health/power/target orbs and party frames (SecureUnitButtonTemplate).
  -- Left / middle / right: spell1, spell3, spell2 — empty right = unit menu (*type2 togglemenu).

  local addon, ns = ...

  ns.ClickCast = ns.ClickCast or {}

  local function trim(s)
    if not s or type(s) ~= "string" then return "" end
    return (s:gsub("^%s+", ""):gsub("%s+$", ""))
  end

  local function clearLeft(orb)
    orb:SetAttribute("*type1", nil)
    orb:SetAttribute("spell1", nil)
  end

  local function clearMiddle(orb)
    orb:SetAttribute("*type3", nil)
    orb:SetAttribute("spell3", nil)
  end

  local function setRightMenu(orb)
    orb:SetAttribute("*type2", "togglemenu")
    orb:SetAttribute("spell2", nil)
  end

  local function setRightSpell(orb, spell)
    orb:SetAttribute("*type2", "spell")
    orb:SetAttribute("spell2", spell)
  end

  -- When holding CTRL: restore the orb's normal unit interaction instead
  -- of click-cast on the SecureUnitButtonTemplate.
  local function setCtrlDefaults(orb, defaultLeftTarget)
    -- Right-click: unit menu
    orb:SetAttribute("ctrl-*type2", "togglemenu")
    orb:SetAttribute("ctrl-spell2", nil)
    orb:SetAttribute("ctrl-type2", "togglemenu")
    orb:SetAttribute("ctrl-spell2", nil)

    -- Middle-click: target unit (matches Blizzard's default behavior)
    orb:SetAttribute("ctrl-*type3", "target")
    orb:SetAttribute("ctrl-spell3", nil)
    orb:SetAttribute("ctrl-type3", "target")
    orb:SetAttribute("ctrl-spell3", nil)

    -- Left-click: only "target" for orbs whose defaultLeftTarget is true.
    if defaultLeftTarget then
      orb:SetAttribute("ctrl-*type1", "target")
      orb:SetAttribute("ctrl-spell1", nil)
      orb:SetAttribute("ctrl-type1", "target")
      orb:SetAttribute("ctrl-spell1", nil)
    else
      orb:SetAttribute("ctrl-*type1", nil)
      orb:SetAttribute("ctrl-spell1", nil)
      orb:SetAttribute("ctrl-type1", nil)
      orb:SetAttribute("ctrl-spell1", nil)
    end
  end

  --- @param rightSpell string empty = right-click unit menu
  local function applyOrb(orb, unitToken, enabled, leftSpell, middleSpell, rightSpell, defaultLeftTarget)
    if not orb or not orb.SetAttribute then return end
    if InCombatLockdown() then return end

    orb:SetAttribute("unit", unitToken)
    leftSpell = trim(leftSpell)
    middleSpell = trim(middleSpell)
    rightSpell = trim(rightSpell)

    if not enabled then
      clearMiddle(orb)
      setRightMenu(orb)
      if defaultLeftTarget then
        orb:SetAttribute("*type1", "target")
        orb:SetAttribute("spell1", nil)
      else
        clearLeft(orb)
      end
      setCtrlDefaults(orb, defaultLeftTarget)
      return
    end

    if rightSpell ~= "" then
      setRightSpell(orb, rightSpell)
    else
      setRightMenu(orb)
    end

    if leftSpell ~= "" then
      orb:SetAttribute("*type1", "spell")
      orb:SetAttribute("spell1", leftSpell)
    else
      if defaultLeftTarget then
        orb:SetAttribute("*type1", "target")
        orb:SetAttribute("spell1", nil)
      else
        clearLeft(orb)
      end
    end

    if middleSpell ~= "" then
      orb:SetAttribute("*type3", "spell")
      orb:SetAttribute("spell3", middleSpell)
    else
      clearMiddle(orb)
    end

    -- CTRL override: always restore normal behavior
    setCtrlDefaults(orb, defaultLeftTarget)
  end

  local function unitIsPartyHeaderMember(u)
    if not u or type(u) ~= "string" then return false end
    if u == "player" then return true end
    return u:match("^party%d+$") ~= nil
  end

  local function applyPartyFrames(db)
    local header = ns.partyHeader
    if not header then return end
    for _, child in ipairs({ header:GetChildren() }) do
      if child.GetAttribute and child.SetAttribute then
        local u = child:GetAttribute("unit")
        if unitIsPartyHeaderMember(u) then
          applyOrb(child, u,
            db.clickCastPartyEnabled == true,
            db.clickCastPartyLeft or "",
            db.clickCastPartyMiddle or "",
            db.clickCastPartyRight or "",
            true)
        end
      end
    end
  end

  function ns.ClickCast.ApplyAll()
    if InCombatLockdown() then return end
    local db = rOrbsDB
    if not db then return end

    local h = _G["rOrbsHealthOrb"]
    local p = _G["rOrbsPowerOrb"]
    local t = _G["rOrbsTargetHealthOrb"]

    if h then
      applyOrb(h, "player",
        db.clickCastHealthEnabled == true,
        db.clickCastHealthLeft or "",
        db.clickCastHealthMiddle or "",
        db.clickCastHealthRight or "",
        true)
    end

    if p then
      applyOrb(p, "player",
        db.clickCastPowerEnabled == true,
        db.clickCastPowerLeft or "",
        db.clickCastPowerMiddle or "",
        db.clickCastPowerRight or "",
        false)
    end

    if t then
      applyOrb(t, "target",
        db.clickCastTargetEnabled == true,
        db.clickCastTargetLeft or "",
        db.clickCastTargetMiddle or "",
        db.clickCastTargetRight or "",
        true)
    end

    applyPartyFrames(db)
  end

  local ev = CreateFrame("Frame")
  ev:RegisterEvent("PLAYER_REGEN_ENABLED")
  ev:RegisterEvent("PLAYER_LOGIN")
  ev:RegisterEvent("PLAYER_ENTERING_WORLD")
  ev:RegisterEvent("GROUP_ROSTER_UPDATE")
  ev:SetScript("OnEvent", function(_, event)
    if event == "PLAYER_REGEN_ENABLED" or event == "PLAYER_LOGIN" or event == "PLAYER_ENTERING_WORLD" or event == "GROUP_ROSTER_UPDATE" then
      C_Timer.After(0, function()
        if ns.ClickCast and ns.ClickCast.ApplyAll then ns.ClickCast.ApplyAll() end
      end)
    end
  end)
