--- Provides uitility functions relating to the Blizzard API.
--
local APIUtils = {}
local AddOnName, nsVars = ...
local ss = nsVars.SS

local UnitAura = UnitAura
local type = type

--- Provides a string representation for a shapeshift id.
--- @param id number The shapeshift id.
--- @return string The shapeshift name.
function APIUtils.shapeshiftToString(id)
  local forms = {
    [0] = "default",
    [1] = "cat",
    [2] = "tree of life",
    [3] = "travel",
    [4] = "aquatic",
    [5] = "bear",
    [27] = "flight",
    [31] = "moonkin",
  };

  return forms[id] or "default"
end

--- Retrieves the text value of a UIDropDownMenu.
--- @param menu  table The UIDropDownMenu object.
--- @return string The text value.
--- @see UIDropDownMenu_SetText().
function APIUtils.UIDropDownMenu_GetText(menu)
  if type(menu) == 'table' and type(menu.Text) == 'table' and type(menu.Text.GetText) == 'function' then
    return menu.Text:GetText()
  else
    ss.Utils.throw(ss.Utils.Errors.ErrorInvalidArgs, "lua", "UIDropDownMenu_GetText",
        { "menu", "UIDropDownMenu", menu, })
  end
end

--- Searches for the matching aura using recursion.
--- @param predicate function The function used to find a match.
--- @param unit string The unit to scan.
--- @param filter string The filter to apply to UnitAura().
--- @param auraIndex number The next index to check.
--- @param predicateArg1 any The first argument for the predicate.
--- @param predicateArg2 any The second argument for the predicate.
--- @param predicateArg3 any The third argument for the predicate.
--- @return table The aura, nil if no match was found.
local function FindAuraRecurse(predicate, unit, filter, auraIndex, predicateArg1, predicateArg2, predicateArg3, ...)
  if ... == nil then
    -- Not found.
    return nil
  end

  if predicate(predicateArg1, predicateArg2, predicateArg3, ...) then
    return ...
  end

  auraIndex = auraIndex + 1
  return FindAuraRecurse(predicate, unit, filter, auraIndex, predicateArg1, predicateArg2, predicateArg3, UnitAura(unit, auraIndex, filter))
end

--- Find an aura by any predicate, you can pass in up to 3 predicate specific parameters
--- The predicate will also receive all aura params, if the aura data matches return true
--- @param predicate function The function used to find a match.
--- @param unit string The unit to scan.
--- @param filter string The filter to apply to UnitAura().
--- @param predicateArg1 any The first argument for the predicate.
--- @param predicateArg2 any The second argument for the predicate.
--- @param predicateArg3 any The third argument for the predicate.
--- @return table The aura, nil if no match was found.
function APIUtils.FindAura(predicate, unit, filter, predicateArg1, predicateArg2, predicateArg3)
  local auraIndex = 1
  return FindAuraRecurse(predicate, unit, filter, auraIndex, predicateArg1, predicateArg2, predicateArg3, UnitAura(unit, auraIndex, filter))
end

do
  --local function NamePredicate(auraNameToFind, _, _, auraName)
  --  return auraNameToFind == auraName;
  --end

  --- The predicate for matching the aura.
  --- @param spellIdToFind number The spellId associated with the aura.
  --- @param spellId number The spellId of the current aura being matched.
  --- @return boolean True if the values match.
  local function SpellIdPredicate(spellIdToFind, _, _, _, _, _, _, _, _, _, _, _, spellId)
    return spellIdToFind == spellId
  end

  --function APIUtils.FindAuraByName(auraName, unit, filter)
  --  return APIUtils.FindAura(NamePredicate, unit, filter, auraName);
  --end

  --- Finds an aura by a given spellId.
  --- @param auraId number The spellId to find.
  --- @param unit string The unit to scan.
  --- @param filter string The filter to apply to UnitAura().
  --- @return table The aura, nil if no match was found.
  function APIUtils.FindAuraById(auraId, unit, filter)
    return APIUtils.FindAura(SpellIdPredicate, unit, filter, auraId)
  end
end

ss.Utils.addModule("APIUtils", APIUtils)
