local tablex = require("core.tablex")
local colors = require("ui.colors")
local consts = require("ui.consts")
local iconConsts = require("ui.iconConsts")
local lamsConsts = require("ui.lamsConsts")
local pickupConsts = require("ui.pickupConsts")
local pickupUtil = require("ui.pickupUtil")
local resourceConsts = require("ui.resourceConsts")
local util = require("ui.util")
local runeLams = require("ui.runeLams")
local Pickup = game.Pickup
local UI = game.UI
local Wallets = game.Wallets
local pickupSlotToSocketResourceFlagTable = {
  [pickupConsts.Slot_PrimaryWeapon] = resourceConsts.RESOURCE_FLAG_SOCKET_WEAPON,
  [pickupConsts.Slot_Blades] = resourceConsts.RESOURCE_FLAG_SOCKET_WEAPON,
  [pickupConsts.Slot_ArmorChest] = resourceConsts.RESOURCE_FLAG_SOCKET_ARMOR,
  [pickupConsts.Slot_ArmorLegs] = resourceConsts.RESOURCE_FLAG_SOCKET_ARMOR,
  [pickupConsts.Slot_ArmorWrist] = resourceConsts.RESOURCE_FLAG_SOCKET_ARMOR,
  [pickupConsts.Slot_ArmorTrinket] = resourceConsts.RESOURCE_FLAG_SOCKET_ARMOR
}
local IsValidSocketIndex = function(socketIndex)
  return socketIndex ~= nil and socketIndex ~= pickupConsts.INVALID_SOCKET_INDEX
end
local GetSocketDisplayName = function(socketIndex)
  local displayName = ""
  if type(socketIndex) == "number" then
    displayName = util.GetLAMSMsg(lamsConsts.RuneSlot) .. " " .. tostring(socketIndex + 1)
  end
  return displayName
end
local GetSocketResourceFlagFromPickupSlot = function(pickupSlotName)
  local socketFlag
  if pickupSlotName ~= nil then
    socketFlag = pickupSlotToSocketResourceFlagTable[pickupSlotName]
  end
  return socketFlag
end
local GetSocketNames = function(pickupName)
  local socketNames = {}
  local currSocketCount = pickupConsts.MAX_SOCKET_COUNT
  local nameIndex = 1
  if pickupName ~= nil then
    currSocketCount = pickupUtil.GetRuneSocketCount(pickupName)
  end
  for socketIndex = 0, currSocketCount - 1 do
    tablex.FastInsert(socketNames, socketIndex, nameIndex)
    nameIndex = nameIndex + 1
  end
  return socketNames
end
local GetRuneInfoRuneID = function(runeInfo)
  local runeId = pickupConsts.INVALID_RUNE_ID
  if runeInfo ~= nil then
    runeId = runeInfo.Id
  end
  return runeId
end
local GetRuneInfoLamsIDs = function(runeInfo)
  local lamsIDs
  if runeInfo ~= nil then
    lamsIDs = runeInfo.LamsNames
  end
  return lamsIDs
end
local GetRuneInfoSocketType = function(runeInfo)
  local socketType
  if runeInfo ~= nil then
    socketType = runeInfo.SocketType
  end
  return socketType
end
local GetRuneInfoPickupID = function(runeInfo)
  local pickupID
  if runeInfo ~= nil then
    pickupID = runeInfo.Pickup
  end
  return pickupID
end
local GetRuneInfoSocketIndex = function(runeInfo)
  local socketIndex
  if runeInfo ~= nil then
    socketIndex = runeInfo.SocketIndex
  end
  return socketIndex
end
local GetRuneInfoPerks = function(runeInfo)
  local perks
  if runeInfo ~= nil then
    perks = runeInfo.Perks
  end
  return perks
end
local GetRuneInfoImprovements = function(runeInfo)
  local improvements = {}
  if runeInfo ~= nil then
    improvements = runeInfo.Improvements
  end
  return improvements
end
local GetRuneInfoSellRecipe = function(runeInfo)
  local sellRecipe
  if runeInfo ~= nil then
    sellRecipe = runeInfo.SellRecipe
  end
  return sellRecipe
end
local GetRuneInfoImprovementAttributeValue = function(runeInfo, attributeName)
  local value = 0
  if attributeName ~= nil then
    local attributeHash = engine.Hash(attributeName)
    local improvements = GetRuneInfoImprovements(runeInfo)
    for _, improvement in ipairs(improvements) do
      if improvement.Attribute == attributeHash then
        value = improvement.Amount
      end
    end
  end
  return value
end
local GetRuneAttributesFromInfo = function(runeInfo)
  local attributes = {
    {name = nil, value = nil}
  }
  for index, attributeName in ipairs(pickupConsts.Attributes) do
    attributes[index] = {}
    attributes[index].name = attributeName
    attributes[index].value = GetRuneInfoImprovementAttributeValue(runeInfo, attributeName)
  end
  return attributes
end
local GetRuneInfoPerksStringTable = function(runeInfo)
  local info = ""
  local perksStringTable = {}
  if runeInfo ~= nil then
    local perks = GetRuneInfoPerks(runeInfo)
    for _, perk in ipairs(perks) do
      tablex.FastInsert(perksStringTable, pickupUtil.GetDisplayName(perk), #perksStringTable + 1)
      tablex.FastInsert(perksStringTable, pickupUtil.GetDescription(perk), #perksStringTable + 1)
    end
  end
  return perksStringTable
end
local RuneInfo_IsSocketed = function(runeInfo)
  local isSocketed = false
  local socketIndex = GetRuneInfoSocketIndex(runeInfo)
  if IsValidSocketIndex(socketIndex) then
    local pickupID = GetRuneInfoPickupID(runeInfo)
    isSocketed = pickupID ~= nil
  end
  return isSocketed
end
local RuneInfo_IsRuneInSocket = function(runeInfo, pickupName, socketIndex)
  local isEquipped = false
  local currSocketIndex = GetRuneInfoSocketIndex(runeInfo)
  if IsValidSocketIndex(currSocketIndex) and pickupUtil.IsValidName(pickupName) then
    local pickupNameHash = engine.Hash(pickupName)
    local currPickupId = GetRuneInfoPickupID(runeInfo)
    isEquipped = socketIndex == currSocketIndex and pickupNameHash == currPickupId
  end
  return isEquipped
end
local RuneInfo_HasPerks = function(runeInfo)
  local perks = GetRuneInfoPerks(runeInfo)
  return perks ~= nil and 0 < #perks
end
local RuneInfo_Compare = function(item, otherItem)
  local a = type(item) == "number" and item or GetRuneInfoRuneID(item)
  local b = type(otherItem) == "number" and otherItem or GetRuneInfoRuneID(otherItem)
  return a == b
end
local IsValidRuneID = function(runeID)
  return runeID ~= nil and runeID ~= pickupConsts.INVALID_RUNE_ID
end
local HasFlag = function(runeID, flag)
  local hasFlag = false
  if IsValidRuneID(runeID) then
    if Wallets.RuneHasAllFlags ~= nil then
      hasFlag = Wallets.RuneHasAllFlags(resourceConsts.WALLET_KRATOS, runeID, flag) or Wallets.RuneHasAllFlags(resourceConsts.WALLET_LOST_ITEMS, runeID, flag)
    else
      hasFlag = Wallets.RuneHasFlag(resourceConsts.WALLET_KRATOS, runeID, {flag}) or Wallets.RuneHasFlag(resourceConsts.WALLET_LOST_ITEMS, runeID, {flag})
    end
  end
  return hasFlag
end
local GetRuneInfo = function(runeID)
  local runeInfo
  if IsValidRuneID(runeID) then
    runeInfo = Wallets.GetRuneInfo(resourceConsts.WALLET_KRATOS, runeID)
  end
  return runeInfo
end
local IsNew = function(runeID)
  local isNew = false
  if IsValidRuneID(runeID) then
    isNew = UI.HasNotification(consts.NotificationTypes.Rune, runeID)
  end
  return isNew
end
local ClearNew = function(runeID)
  if IsNew(runeID) then
    UI.ClearNotification(consts.NotificationTypes.Rune, runeID)
  end
end
local GetRunesInPickup = function(pickupName)
  local runesInPickup = Wallets.FindPickupRunes(resourceConsts.WALLET_KRATOS, pickupName)
  return runesInPickup
end
local GetRunes = function(excludeSocketedRunes, pickupName, socketIndex, sortingInfo)
  local allRuneIDs = Wallets.GetAllRunes(resourceConsts.WALLET_KRATOS, {}, resourceConsts.RESOURCE_FLAG_SOCKET_ARMOR, resourceConsts.POWER_LEVEL_SORTING)
  local allRuneInfoTables = {}
  Wallets.SortRuneList(resourceConsts.WALLET_KRATOS, allRuneIDs, resourceConsts.RARITY_SORTING)
  if sortingInfo == resourceConsts.POWER_LEVEL_SORTING then
    local tiers = {
      "Tier09",
      "Tier08",
      "Tier07",
      "Tier06",
      "Tier05",
      "Tier04",
      "Tier03",
      "Tier02",
      "Tier01"
    }
    Wallets.SortRuneList(resourceConsts.WALLET_KRATOS, allRuneIDs, tiers)
  end
  if sortingInfo ~= resourceConsts.RARITY_SORTING then
    Wallets.SortRuneList(resourceConsts.WALLET_KRATOS, allRuneIDs, sortingInfo)
  end
  for i = #allRuneIDs, 1, -1 do
    local currRuneID = allRuneIDs[i]
    local currRuneInfo = GetRuneInfo(currRuneID)
    local keepRuneInfo = true
    if excludeSocketedRunes and RuneInfo_IsSocketed(currRuneInfo) and not RuneInfo_IsRuneInSocket(currRuneInfo, pickupName, socketIndex) then
      keepRuneInfo = false
      table.remove(allRuneIDs, i)
    end
    if keepRuneInfo then
      table.insert(allRuneInfoTables, 1, currRuneInfo)
    end
  end
  return allRuneIDs, allRuneInfoTables
end
local GetRuneInfoInSocketFromPickup = function(pickupName, socketIndex)
  local runeInfoInSocket
  if Wallets.FindRuneInfoInSocket ~= nil then
    runeInfoInSocket = Wallets.FindRuneInfoInSocket(resourceConsts.WALLET_KRATOS, pickupName, socketIndex)
  else
    local runesInPickup = GetRunesInPickup(pickupName)
    for _, runeID in ipairs(runesInPickup) do
      local currRuneInfo = GetRuneInfo(runeID)
      if RuneInfo_IsRuneInSocket(currRuneInfo, pickupName, socketIndex) then
        runeInfoInSocket = currRuneInfo
      end
    end
  end
  return runeInfoInSocket
end
local GetTierFromID = function(runeID)
  local tier
  for _, flag in ipairs(resourceConsts.TIER_FLAGS) do
    local hasFlag = HasFlag(runeID, flag)
    if hasFlag == true then
      tier = flag
      break
    end
  end
  if tier == nil then
    tier = resourceConsts.TIER_FLAGS[1]
    print("No tier was discovered on a rune to display in the stat card.")
  end
  return tier
end
local GetTierIndexFromID = function(runeID)
  local tierIndex
  for index, flag in ipairs(resourceConsts.TIER_FLAGS) do
    local hasFlag = HasFlag(runeID, flag)
    if hasFlag == true then
      tierIndex = index
      break
    end
  end
  assert(tierIndex ~= nil, "No tier was discovered on a rune to display in the stat card.")
  return tierIndex
end
local GetIconShapeFlagFromID = function(runeID)
  local shapeFlag
  for _, flag in ipairs(resourceConsts.RUNE_SHAPE_FLAGS) do
    if HasFlag(runeID, flag) then
      shapeFlag = flag
      break
    end
  end
  return shapeFlag
end
local GetIconQualityFlagFromID = function(runeID)
  local shapeFlag
  for _, flag in ipairs(resourceConsts.RUNE_QUALITY_FLAGS) do
    if HasFlag(runeID, flag) then
      shapeFlag = flag
      break
    end
  end
  return shapeFlag
end
local GetRuneIconFromID = function(runeID)
  local runeIcon = ""
  if IsValidRuneID(runeID) then
    local shapeFlag = GetIconShapeFlagFromID(runeID)
    local qualityFlag = GetIconQualityFlagFromID(runeID)
    if shapeFlag ~= nil and qualityFlag ~= nil then
      runeIcon = iconConsts.Rune[shapeFlag][qualityFlag]
    else
      runeIcon = iconConsts.Rune.B_Oval.Rough
    end
  end
  return runeIcon
end
local GetRarityFromID = function(runeID)
  for idx, rarityFlag in pairs(resourceConsts.RARITY_FLAGS) do
    local hasRarity = HasFlag(runeID, rarityFlag)
    if hasRarity then
      return rarityFlag, idx
    end
  end
  return resourceConsts.RESOURCE_FLAG_ECONOMY, 1
end
local GetPowerLevelFromID = function(runeID)
  local powerLevel = 0
  for index, flag in ipairs(resourceConsts.TIER_FLAGS) do
    local hasFlag = HasFlag(runeID, flag)
    if hasFlag == true then
      powerLevel = index
      break
    end
  end
  return powerLevel
end
local GetRuneColorFromID = function(runeID)
  for rarityFlag, color in pairs(colors.RARITY) do
    local hasRarity = HasFlag(runeID, rarityFlag)
    if hasRarity then
      return color
    end
  end
  return colors.BLACK
end
local GetEffectFlagFromID = function(runeID)
  local effectFlag
  if IsValidRuneID(runeID) then
    local isTypeWithEffect = resourceConsts.RECIPE_SUBMENUS_CATEGORY_SORTING_GROUP_INDEX[resourceConsts.RESOURCE_FLAG_RUNE] == resourceConsts.SORTING_GROUP_RARITY_STATS_EFFECTS
    if isTypeWithEffect == true then
      for _, flag in ipairs(resourceConsts.EFFECTS_SORTING) do
        if HasFlag(runeID, flag) then
          effectFlag = flag
          break
        end
      end
    end
  end
  return effectFlag
end
local UnsocketRune = function(pickupName, socketIndex)
  assert(pickupName ~= nil, "Attempted to call UnsocketRune without a pickup!")
  if IsValidSocketIndex(socketIndex) then
    local currEquippedRuneInfo = GetRuneInfoInSocketFromPickup(pickupName, socketIndex)
    local currEquippedRuneID = GetRuneInfoRuneID(currEquippedRuneInfo)
    local currPickupSlot = Pickup.GetSlotName(pickupName)
    local currSocketType = GetSocketResourceFlagFromPickupSlot(currPickupSlot)
    Wallets.SocketRune(resourceConsts.WALLET_KRATOS, currEquippedRuneID, pickupConsts.INVALID_SOCKET_INDEX, pickupName, currSocketType, socketIndex)
    return currEquippedRuneID
  end
end
local UnsocketAllRunes = function(pickupName)
  if pickupName then
    local runesInPickup = GetRunesInPickup(pickupName)
    local currSocketCount = pickupUtil.GetRuneSocketCount(pickupName)
    for iSocket = 0, currSocketCount - 1 do
      if IsValidSocketIndex(iSocket) then
        local currEquippedRuneInfo = GetRuneInfoInSocketFromPickup(pickupName, iSocket)
        if currEquippedRuneInfo ~= nil then
          local currEquippedRuneID = GetRuneInfoRuneID(currEquippedRuneInfo)
          local currPickupSlot = Pickup.GetSlotName(pickupName)
          local currSocketType = GetSocketResourceFlagFromPickupSlot(currPickupSlot)
          Wallets.SocketRune(resourceConsts.WALLET_KRATOS, currEquippedRuneID, pickupConsts.INVALID_SOCKET_INDEX, pickupName, currSocketType, iSocket)
        end
      end
    end
  end
end
local SocketRune = function(walletName, pickupName, socketIndex, newRuneID, currEquippedRuneID)
  assert(walletName ~= nil, "Attempted to call SocketRune without a wallet!")
  assert(pickupName ~= nil, "Attempted to call SocketRune without a pickup!")
  assert(currEquippedRuneID ~= nil, "Attempted to call SocketRune without a currEquippedRuneID!")
  if newRuneID == pickupConsts.INVALID_SOCKET_INDEX then
    UnsocketRune(pickupName, socketIndex)
    return
  end
  local wasSocketed = false
  if IsValidSocketIndex(socketIndex) and IsValidRuneID(newRuneID) then
    local currPickupSlot = Pickup.GetSlotName(pickupName)
    local currSocketType = GetSocketResourceFlagFromPickupSlot(currPickupSlot)
    wasSocketed = Wallets.SocketRune(walletName, currEquippedRuneID, newRuneID, pickupName, currSocketType, socketIndex)
  end
  return wasSocketed
end
local PreviewRune = function(walletName, pickupName, socketIndex, newRuneID, currEquippedRuneID)
  assert(walletName ~= nil, "Attempted to call SocketRune without a wallet!")
  assert(pickupName ~= nil, "Attempted to call SocketRune without a pickup!")
  assert(currEquippedRuneID ~= nil, "Attempted to call SocketRune without a currEquippedRuneID!")
  if newRuneID == pickupConsts.INVALID_SOCKET_INDEX then
    UnsocketRune(pickupName, socketIndex)
    return
  end
  local wasSocketed = false
  if IsValidSocketIndex(socketIndex) and IsValidRuneID(newRuneID) then
    local currPickupSlot = Pickup.GetSlotName(pickupName)
    local currSocketType = GetSocketResourceFlagFromPickupSlot(currPickupSlot)
    wasSocketed = Wallets.SocketRune(walletName, currEquippedRuneID, newRuneID, pickupName, currSocketType, socketIndex)
  end
  return wasSocketed
end
local ExchangeRune = function(buyerWallet, sellerWallet, currRuneID)
  local currRuneInfo = GetRuneInfo(currRuneID)
  local currSellRecipe = GetRuneInfoSellRecipe(currRuneInfo)
  local wasExchanged = false
  if not util.IsStringNilOrEmpty(currSellRecipe) then
    wasExchanged = Wallets.ExchangeRune(buyerWallet, sellerWallet, currRuneID)
  end
  return wasExchanged
end
local HasMemorySpaceForRune = function()
  local hasSpace = true
  if Wallets.HasMemorySpaceForRune ~= nil then
    hasSpace = Wallets.HasMemorySpaceForRune()
  end
  return hasSpace
end
local UnsocketAndKeepRuneIDs = function(pickupName, runeIDTable)
  local socketCount = pickupUtil.GetRuneSocketCount(pickupName)
  for socketIndex = 0, socketCount - 1 do
    local unsocketedRuneID = UnsocketRune(pickupName, socketIndex)
    if IsValidRuneID(unsocketedRuneID) then
      tablex.FastInsert(runeIDTable, unsocketedRuneID, #runeIDTable + 1)
    end
  end
  return socketCount
end
local SocketSwappedRunes = function(pickupSocketCount, runeIDTable, pickupName, statsCard)
  for socketIndex = 0, pickupSocketCount - 1 do
    local runeIndex = socketIndex + 1
    local runeID = runeIDTable[runeIndex]
    if runeID ~= nil then
      SocketRune(resourceConsts.WALLET_KRATOS, pickupName, socketIndex, runeID, pickupConsts.INVALID_RUNE_ID)
      if statsCard ~= nil then
        statsCard:AnimateUpgradeSlot(runeIndex)
      end
    end
  end
end
local SwapRunes = function(currentPickupName, equippedPickupName, statsCard, comparisonStatsCard)
  if pickupUtil.IsValidName(currentPickupName) and pickupUtil.IsValidName(equippedPickupName) then
    local runesOnCurrentItem = {}
    local currPickupSocketCount = UnsocketAndKeepRuneIDs(currentPickupName, runesOnCurrentItem)
    local runesOnEquippedItem = {}
    local equippedPickupSocketCount = UnsocketAndKeepRuneIDs(equippedPickupName, runesOnEquippedItem)
    local resistanceIndex = tablex.Index(pickupConsts.Attributes, "Resistance")
    SocketSwappedRunes(currPickupSocketCount, runesOnEquippedItem, currentPickupName, statsCard)
    SocketSwappedRunes(equippedPickupSocketCount, runesOnCurrentItem, equippedPickupName, comparisonStatsCard)
    local deltaTable = {}
    for i, _ in ipairs(pickupConsts.Attributes) do
      deltaTable[i] = 0
    end
    deltaTable[pickupConsts.PowerLevelIndex] = 0
    deltaTable[pickupConsts.MaxHealthIndex] = 0
    for _, runeID in ipairs(runesOnEquippedItem) do
      local runeInfo = GetRuneInfo(runeID)
      local runeAttributes = GetRuneAttributesFromInfo(runeInfo)
      for i, _ in ipairs(runeAttributes) do
        deltaTable[i] = deltaTable[i] - runeAttributes[i].value
      end
      deltaTable[pickupConsts.PowerLevelIndex] = deltaTable[pickupConsts.PowerLevelIndex] - GetRuneInfoImprovementAttributeValue(runeInfo, "PowerLevel")
      deltaTable[pickupConsts.MaxHealthIndex] = deltaTable[pickupConsts.MaxHealthIndex] - util.Round(runeAttributes[resistanceIndex].value / 2)
    end
    for _, runeID in ipairs(runesOnCurrentItem) do
      local runeInfo = GetRuneInfo(runeID)
      local runeAttributes = GetRuneAttributesFromInfo(runeInfo)
      for i, _ in ipairs(runeAttributes) do
        deltaTable[i] = deltaTable[i] + runeAttributes[i].value
      end
      deltaTable[pickupConsts.PowerLevelIndex] = deltaTable[pickupConsts.PowerLevelIndex] + GetRuneInfoImprovementAttributeValue(runeInfo, "PowerLevel")
      deltaTable[pickupConsts.MaxHealthIndex] = deltaTable[pickupConsts.MaxHealthIndex] + util.Round(runeAttributes[resistanceIndex].value / 2)
    end
    return deltaTable
  end
end
local SetRuneListToCurrentlyEquipped = function(pickupName, socketsList, runeList, socketIndex, useOnGainFocus)
  if pickupUtil.IsValidName(pickupName) and runeList ~= nil then
    local currEquippedRuneInfo = GetRuneInfoInSocketFromPickup(pickupName, socketIndex)
    local currEquippedRuneID = GetRuneInfoRuneID(currEquippedRuneInfo)
    socketsList:SelectItem(currEquippedRuneID, useOnGainFocus)
  end
end
local SetAllRuneListsToCurrentlyEquipped = function(pickupName, menu, socketsList)
  if pickupName ~= nil and socketsList ~= nil then
    local socketsListButtons = socketsList:GetButtons()
    for _, socketButton in ipairs(socketsListButtons) do
      local socketIndex = socketButton:get_item()
      SetRuneListToCurrentlyEquipped(pickupName, socketsList, menu:GetList(socketIndex), socketIndex, false)
      socketButton:Update()
    end
  end
end
local DeactivateRuneListsBySocketsList = function(pickupName, menu, socketsList, socketToNotReset, clearButtons)
  if pickupName ~= nil then
    local socketsListButtons = socketsList:GetButtons()
    for _, socketButton in ipairs(socketsListButtons) do
      local socketIndex = socketButton:get_item()
      local currRuneList = menu:GetList(socketIndex)
      if currRuneList:get_active() then
        local doNotResetThisSocketList = socketToNotReset ~= nil and socketIndex == socketToNotReset
        if not doNotResetThisSocketList then
          SetRuneListToCurrentlyEquipped(pickupName, socketsList, currRuneList, socketIndex, false)
          socketButton:Update()
        end
        currRuneList:Deactivate(clearButtons, clearButtons)
      end
    end
  end
end
local ActivateRuneListBySocketIndex = function(pickupName, menu, socketsList, socketIndex)
  DeactivateRuneListsBySocketsList(pickupName, menu, socketsList, socketIndex, false)
  local selectedRuneList = menu:GetList(socketIndex)
  if selectedRuneList ~= nil then
    local showList = false
    local useOnGainFocus = true
    selectedRuneList:Activate(showList, useOnGainFocus)
  end
end
local ShouldUseItemCard = function(runeID)
  local developmentEnabled = game.CHECK_FEATURE("DISABLE_ITEM_CARDS")
  developmentEnabled = developmentEnabled and engine.VFSGetBool("/UI/Disable Item Acquire") == 0
  return developmentEnabled and not HasFlag(runeID, resourceConsts.RESOURCE_FLAG_DONOTDISPLAYRUNE) and HasFlag(runeID, resourceConsts.RESOURCE_FLAG_UNIQUE_RUNE)
end
local GetRuneDisplayNameFromList = function(runeInfo)
  local displayName
  local lamsKey = ""
  if runeInfo ~= nil then
    local runeID = GetRuneInfoRuneID(runeInfo)
    if RuneInfo_HasPerks(runeInfo) then
      local perks = GetRuneInfoPerks(runeInfo)
      lamsKey = lamsKey .. Pickup.GetName(perks[1])
    else
      lamsKey = lamsKey .. GetRarityFromID(runeID)
    end
    local attributes = GetRuneAttributesFromInfo(runeInfo)
    local collapsedAttributes = {}
    local attributeCount = 0
    for _, attribute in pairs(attributes) do
      if 0 < attribute.value then
        if collapsedAttributes[attribute.name] ~= nil then
          collapsedAttributes[attribute.name] = collapsedAttributes[attribute.name] + attribute.value
        else
          collapsedAttributes[attribute.name] = attribute.value
          attributeCount = attributeCount + 1
        end
      end
    end
    if attributeCount == 1 then
      for name, _ in pairs(collapsedAttributes) do
        lamsKey = lamsKey .. "_" .. name .. "_" .. name
      end
    elseif attributeCount == 2 then
      local allAttributes = {}
      for k, _ in pairs(collapsedAttributes) do
        table.insert(allAttributes, k)
      end
      table.sort(allAttributes, function(k1, k2)
        return pickupConsts.AttributeSortOrder[k1] < pickupConsts.AttributeSortOrder[k2]
      end)
      for _, a in ipairs(allAttributes) do
        lamsKey = lamsKey .. "_" .. a
      end
    end
    displayName = util.GetLAMSMsg(runeLams[lamsKey])
  end
  return displayName, runeLams[lamsKey]
end
local GetRuneInfoDisplayName = function(runeInfo)
  if runeInfo ~= nil then
    local runeID = GetRuneInfoRuneID(runeInfo)
    if not HasFlag(runeID, resourceConsts.RESOURCE_FLAG_UNIQUE_RUNE) and not HasFlag(runeID, resourceConsts.RESOURCE_FLAG_TIER_07) then
      local name, id = GetRuneDisplayNameFromList(runeInfo)
      if id ~= nil then
        return name
      end
    end
  end
  local displayName = ""
  if runeInfo ~= nil then
    local lamsIDs = GetRuneInfoLamsIDs(runeInfo)
    if lamsIDs == nil then
      local lamsId = runeInfo.LamsNameId
      if lamsId ~= nil then
        displayName = util.GetLAMSMsg(lamsId, "Rune ID: " .. GetRuneInfoRuneID(runeInfo))
      end
    else
      for _, lams in ipairs(lamsIDs) do
        displayName = displayName .. util.GetLAMSMsg(lams, "Rune ID: " .. GetRuneInfoRuneID(runeInfo)) .. " "
      end
    end
  end
  return displayName
end
local GetRuneDisplayNameFromID = function(runeID)
  local runeInfo = GetRuneInfo(runeID)
  return GetRuneInfoDisplayName(runeInfo)
end
return {
  IsValidSocketIndex = IsValidSocketIndex,
  GetSocketDisplayName = GetSocketDisplayName,
  GetSocketResourceFlagFromPickupSlot = GetSocketResourceFlagFromPickupSlot,
  GetSocketNames = GetSocketNames,
  GetRuneInfoRuneID = GetRuneInfoRuneID,
  GetRuneInfoSocketType = GetRuneInfoSocketType,
  GetRuneInfoPickupID = GetRuneInfoPickupID,
  GetRuneInfoSocketIndex = GetRuneInfoSocketIndex,
  GetRuneInfoPerks = GetRuneInfoPerks,
  GetRuneInfoImprovements = GetRuneInfoImprovements,
  GetRuneInfoSellRecipe = GetRuneInfoSellRecipe,
  GetRuneInfoImprovementAttributeValue = GetRuneInfoImprovementAttributeValue,
  GetRuneAttributesFromInfo = GetRuneAttributesFromInfo,
  GetRuneInfoPerksStringTable = GetRuneInfoPerksStringTable,
  RuneInfo_IsSocketed = RuneInfo_IsSocketed,
  RuneInfo_IsRuneInSocket = RuneInfo_IsRuneInSocket,
  RuneInfo_HasPerks = RuneInfo_HasPerks,
  RuneInfo_Compare = RuneInfo_Compare,
  IsValidRuneID = IsValidRuneID,
  HasFlag = HasFlag,
  GetRuneInfo = GetRuneInfo,
  IsNew = IsNew,
  ClearNew = ClearNew,
  GetRunesInPickup = GetRunesInPickup,
  GetRunes = GetRunes,
  GetRuneInfoInSocketFromPickup = GetRuneInfoInSocketFromPickup,
  GetTierFromID = GetTierFromID,
  GetTierIndexFromID = GetTierIndexFromID,
  GetRuneIconFromID = GetRuneIconFromID,
  GetRarityFromID = GetRarityFromID,
  GetPowerLevelFromID = GetPowerLevelFromID,
  GetRuneColorFromID = GetRuneColorFromID,
  GetEffectFlagFromID = GetEffectFlagFromID,
  UnsocketAllRunes = UnsocketAllRunes,
  UnsocketRune = UnsocketRune,
  SocketRune = SocketRune,
  PreviewRune = PreviewRune,
  ExchangeRune = ExchangeRune,
  HasMemorySpaceForRune = HasMemorySpaceForRune,
  SwapRunes = SwapRunes,
  SetAllRuneListsToCurrentlyEquipped = SetAllRuneListsToCurrentlyEquipped,
  DeactivateRuneListsBySocketsList = DeactivateRuneListsBySocketsList,
  ActivateRuneListBySocketIndex = ActivateRuneListBySocketIndex,
  ShouldUseItemCard = ShouldUseItemCard,
  GetRuneInfoDisplayName = GetRuneInfoDisplayName,
  GetRuneDisplayNameFromID = GetRuneDisplayNameFromID
}
