local tablex = require("core.tablex")
local consts = require("ui.consts")
local colors = require("ui.colors")
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 Resources = game.Resources
local UI = game.UI
local Wallets = game.Wallets
local IsValidResourceName = function(resourceName)
  return not util.IsStringNilOrEmpty(resourceName)
end
local HasFlag = function(resourceName, resourceFlag)
  assert(resourceFlag ~= nil, "Attempted to call HasFlag without a resource flag!")
  local hasFlag = false
  if IsValidResourceName(resourceName) then
    hasFlag = Resources.HasFlag(resourceName, resourceFlag)
  end
  return hasFlag
end
local GetDisplayName = function(resourceName)
  local displayName = resourceName .. " DisplayName Not Found"
  if IsValidResourceName(resourceName) then
    if HasFlag(resourceName, resourceConsts.RESOURCE_FLAG_PICKUP) then
      displayName = pickupUtil.GetDisplayName(resourceName)
    else
      local idExists, lamsNameId = Resources.GetLamsNameId(resourceName)
      if idExists == true then
        displayName = util.GetLAMSMsg(lamsNameId, resourceName)
      end
    end
  end
  return displayName
end
local GetDescription = function(resourceName)
  local description = resourceName .. " Description Not Found"
  if IsValidResourceName(resourceName) then
    if HasFlag(resourceName, resourceConsts.RESOURCE_FLAG_PICKUP) then
      description = pickupUtil.GetDescription(resourceName)
    else
      local idExists, lamsDescriptionId = Resources.GetLamsDescriptionId(resourceName)
      if idExists == true then
        description = util.GetLAMSMsg(lamsDescriptionId, resourceName)
      end
    end
  end
  return description
end
local GetIcon = function(resourceName)
  local iconMacro = ""
  if IsValidResourceName(resourceName) then
    if HasFlag(resourceName, resourceConsts.RESOURCE_FLAG_PICKUP) then
      iconMacro = pickupUtil.GetIcon(resourceName)
    else
      local iconExists, iconName = Resources.GetIconName(resourceName)
      if iconExists == true then
        iconMacro = iconName
      end
    end
  end
  return iconMacro
end
local GetRarity = function(resourceName)
  local rarity
  local index = -1
  if IsValidResourceName(resourceName) then
    for idx, flag in ipairs(resourceConsts.RARITY_FLAGS) do
      if HasFlag(resourceName, flag) then
        rarity = flag
        index = idx
        break
      end
    end
  end
  return rarity, index
end
local GetRarityColor = function(resourceName)
  local rarity = GetRarity(resourceName)
  local color = colors.RARITY[resourceConsts.RESOURCE_FLAG_ECONOMY]
  if rarity ~= nil then
    color = colors.RARITY[rarity]
  end
  return color
end
local GetAmount = function(resourceName)
  local amount = 0
  if IsValidResourceName(resourceName) then
    amount = Wallets.GetResourceValue(resourceConsts.WALLET_KRATOS, resourceName)
    if amount <= 0 and HasFlag(resourceName, resourceConsts.RESOURCE_FLAG_SAVEONLY) then
      amount = Wallets.GetResourceValue(resourceConsts.WALLET_KRATOS_SAVEONLY, resourceName)
    end
    if amount < 0 then
      amount = 0
    end
  end
  return amount
end
local GetMax = function(resourceName)
  local max = 0
  if IsValidResourceName(resourceName) then
    max = Resources.GetMax(resourceName)
  end
  return max
end
local IsResourceAPickup = function(resourceName)
  local isAPickup = false
  if IsValidResourceName(resourceName) then
    isAPickup = HasFlag(resourceName, resourceConsts.RESOURCE_FLAG_PICKUP)
  end
  return isAPickup
end
local IsResourceAGem = function(resourceName)
  if IsValidResourceName(resourceName) then
    for _, slotFlag in ipairs(pickupConsts.WeaponSpecialsSlots) do
      local hasFlag = HasFlag(resourceName, slotFlag)
      if hasFlag == true then
        return true
      end
    end
  end
  return false
end
local IsTrinket = function(resourceName)
  assert(resourceName ~= nil, "Resource name passed into ResourceUtil::IsTrinket was nil.")
  return (HasFlag(resourceName, "ArmorTrinket"))
end
local AtLimit = function(resourceName)
  local atLimit = false
  local max = 1
  if IsValidResourceName(resourceName) then
    if not IsResourceAGem(resourceName) then
      max = GetMax(resourceName)
    end
    atLimit = max <= GetAmount(resourceName)
  end
  return atLimit
end
local HasResource = function(resourceName)
  local hasResource = false
  if IsValidResourceName(resourceName) then
    hasResource = Wallets.HasResource(resourceConsts.WALLET_KRATOS, resourceName) or resourceName == pickupConsts.Shield
  end
  return hasResource
end
local ShouldUseLargeRow = function(resourceName)
  local rarity = GetRarity(resourceName)
  return rarity == resourceConsts.RESOURCE_FLAG_LEGENDARY or rarity == resourceConsts.RESOURCE_FLAG_EPIC
end
local ShouldUseItemCard = function(resourceName, restrictedMode)
  local isGem
  if restrictedMode then
    isGem = HasFlag(resourceName, resourceConsts.RESOURCE_FLAG_WEAPON_SPECIAL_SON)
  else
    isGem = IsResourceAGem(resourceName)
  end
  isGem = isGem and Wallets.GetResourceValue("HERO", resourceName) == 1
  local isWeaponComponent = (HasFlag(resourceName, resourceConsts.RESOURCE_FLAG_WEAPON_COMPONENT) or HasFlag(resourceName, resourceConsts.RESOURCE_FLAG_WEAPON_COMPONENT_BLADES)) and not restrictedMode
  local isArmorTrinket = HasFlag(resourceName, resourceConsts.RESOURCE_FLAG_ARMOR_TRINKET) and not restrictedMode
  local isHealthUpgrade = HasFlag(resourceName, resourceConsts.RESOURCE_HEALTH_UPGRADE) and not restrictedMode
  local isRageUpgrade = HasFlag(resourceName, resourceConsts.RESOURCE_RAGE_UPGRADE) and not restrictedMode
  local isUniqueResource = HasFlag(resourceName, resourceConsts.RESOURCE_FLAG_UNIQUE) and not restrictedMode
  local isFirstTime = false
  local developmentEnabled = game.CHECK_FEATURE("DISABLE_ITEM_CARDS")
  developmentEnabled = developmentEnabled and engine.VFSGetBool("/UI/Disable Item Acquire") == 0
  return (isGem or isWeaponComponent or isArmorTrinket or isHealthUpgrade or isRageUpgrade or isUniqueResource or isFirstTime) and developmentEnabled
end
local IsNew = function(resourceName)
  local isNew = false
  if IsValidResourceName(resourceName) then
    isNew = UI.HasNotification(consts.NotificationTypes.Resource, resourceName)
  end
  return isNew
end
local ClearNew = function(resourceName)
  if IsNew(resourceName) then
    UI.ClearNotification(consts.NotificationTypes.Resource, resourceName)
  end
end
local DetermineIfCanCompare = function(resourceName, itemIsEquipped, resourceFlag)
  local isValid = true
  return not itemIsEquipped and resourceFlag ~= resourceConsts.INFO_CARD_ID_GEM and resourceFlag ~= resourceConsts.RESOURCE_FLAG_RUNE and isValid
end
local GetSound = function(resourceName)
  local sound = "SND_UX_HUD_Item_Notification_Basic"
  if resourceName == "Hacksilver" then
    sound = "SND_UX_HUD_Item_Notification_Hacksilver"
  elseif HasFlag(resourceName, resourceConsts.RESOURCE_FLAG_EXPERIENCE) then
    sound = "SND_UX_Experience_Gained"
  elseif HasFlag(resourceName, resourceConsts.RESOURCE_FLAG_COMMON) then
    sound = "SND_UX_HUD_Item_Notification_Common"
  elseif HasFlag(resourceName, resourceConsts.RESOURCE_FLAG_RARE) then
    sound = "SND_UX_HUD_Item_Notification_Rare"
  elseif HasFlag(resourceName, resourceConsts.RESOURCE_FLAG_LEGENDARY) then
    sound = "SND_UX_HUD_Item_Notification_Legendary"
  elseif HasFlag(resourceName, resourceConsts.RESOURCE_FLAG_EPIC) then
    sound = "SND_UX_HUD_Item_Notification_Epic"
  elseif HasFlag(resourceName, resourceConsts.RESOURCE_FLAG_PERFECT) then
    sound = "SND_UX_HUD_Item_Notification_Epic"
  end
  return sound
end
local GetArmorFlag = function(resourceName)
  local armorFlag
  if IsValidResourceName(resourceName) then
    for _, flag in ipairs(resourceConsts.ARMOR_FLAGS) do
      if HasFlag(resourceName, flag) then
        armorFlag = flag
        break
      end
    end
  end
  return armorFlag
end
local GetEffectFlag = function(slotName, resourceName)
  local effectFlag
  if IsValidResourceName(resourceName) then
    local isTypeWithEffect = resourceConsts.RECIPE_SUBMENUS_CATEGORY_SORTING_GROUP_INDEX[slotName] == resourceConsts.SORTING_GROUP_RARITY_STATS_EFFECTS
    if isTypeWithEffect == true then
      for _, flag in ipairs(resourceConsts.EFFECTS_SORTING) do
        if HasFlag(resourceName, flag) then
          effectFlag = flag
          break
        end
      end
    end
  end
  return effectFlag
end
local AssembleArmorMaterialSwapName = function(slotName, resourceName)
  local swapName = resourceName
  if slotName ~= nil then
    local armorFlag = GetArmorFlag(resourceName)
    if armorFlag == nil then
      swapName = slotName
    else
      swapName = slotName .. "_" .. armorFlag
    end
  end
  return swapName
end
local GetMaterialSwapName = function(resourceName)
  local materialSwapName = consts.EMPTY_MATERIAL_NAME
  if resourceName == pickupConsts.SonQuiver then
    resourceName = pickupConsts.SonBow
  end
  if IsValidResourceName(resourceName) then
    if resourceName == pickupConsts.Axe or resourceName == pickupConsts.SonBow then
      materialSwapName = resourceName
      local stage = pickupUtil.GetProfileStage(resourceName)
      if 0 < stage then
        materialSwapName = materialSwapName .. stage
      end
    elseif HasFlag(resourceName, pickupConsts.Slot_ArmorChest) then
      materialSwapName = AssembleArmorMaterialSwapName(pickupConsts.Slot_ArmorChest, resourceName)
    elseif HasFlag(resourceName, pickupConsts.Slot_ArmorLegs) then
      materialSwapName = AssembleArmorMaterialSwapName(pickupConsts.Slot_ArmorLegs, resourceName)
    elseif HasFlag(resourceName, pickupConsts.Slot_ArmorWrist) then
      materialSwapName = AssembleArmorMaterialSwapName(pickupConsts.Slot_ArmorWrist, resourceName)
    elseif HasFlag(resourceName, pickupConsts.Slot_SonArmor) then
      materialSwapName = AssembleArmorMaterialSwapName(pickupConsts.Slot_SonArmor, resourceName)
    elseif HasFlag(resourceName, "ArmorShield") then
      materialSwapName = "KratosShield_01"
    else
      materialSwapName = resourceName
    end
  end
  return materialSwapName
end
local GetIconText = function(resourceName)
  local iconText = ""
  if IsValidResourceName(resourceName) then
    if iconConsts.GetIcon(resourceName) ~= nil then
      iconText = iconConsts.GetIcon(resourceName)
    else
      print("WARNING: Icon not found for resource: " .. resourceName)
    end
  end
  return iconText
end
local GetResources = function(walletName, includeTypes, excludeTypes, sortingInfo, forceAllFlags)
  assert(walletName ~= nil, "Attempted to call GetResourcesInWallet with no wallet!")
  if walletName ~= resourceConsts.WALLET_KRATOS then
    local resourceList = Wallets.GetResourcesWithFlags(walletName, includeTypes, excludeTypes, resourceConsts.POWER_LEVEL_SORTING)
    Wallets.SortResourceList(walletName, resourceList, resourceConsts.RARITY_SORTING)
    if sortingInfo ~= resourceConsts.RARITY_SORTING then
      Wallets.SortResourceList(walletName, resourceList, sortingInfo)
    end
    return resourceList
  end
  local defaultList, saveOnlyList
  if forceAllFlags then
    defaultList = Wallets.GetResourcesWithAllFlags(walletName, includeTypes, excludeTypes, resourceConsts.POWER_LEVEL_SORTING)
    saveOnlyList = Wallets.GetResourcesWithAllFlags(resourceConsts.WALLET_KRATOS_SAVEONLY, includeTypes, excludeTypes, resourceConsts.POWER_LEVEL_SORTING)
  else
    defaultList = Wallets.GetResourcesWithFlags(walletName, includeTypes, excludeTypes, resourceConsts.POWER_LEVEL_SORTING)
    saveOnlyList = Wallets.GetResourcesWithFlags(resourceConsts.WALLET_KRATOS_SAVEONLY, includeTypes, excludeTypes, resourceConsts.POWER_LEVEL_SORTING)
  end
  Wallets.SortResourceList(walletName, defaultList, resourceConsts.RARITY_SORTING)
  Wallets.SortResourceList(resourceConsts.WALLET_KRATOS_SAVEONLY, saveOnlyList, resourceConsts.RARITY_SORTING)
  if sortingInfo ~= resourceConsts.RARITY_SORTING then
    Wallets.SortResourceList(walletName, defaultList, sortingInfo)
    Wallets.SortResourceList(resourceConsts.WALLET_KRATOS_SAVEONLY, saveOnlyList, sortingInfo)
  end
  if saveOnlyList ~= nil then
    for _, sResource in ipairs(saveOnlyList) do
      local duplicateFound = false
      if defaultList ~= nil then
        for _, dResource in ipairs(defaultList) do
          if sResource == dResource then
            duplicateFound = true
          end
        end
        if not duplicateFound then
          defaultList[#defaultList + 1] = sResource
        end
      end
    end
  end
  return defaultList
end
local GetPickupsInSlotByCharacter = function(pickupSlotName, character, sortingInfo)
  local pickupList = {}
  local itemIndex = 1
  if pickupUtil.IsValidSlotName(pickupSlotName) then
    local characterResourceFlag = character == pickupConsts.TAG_PICKUP_KRATOS and resourceConsts.RESOURCE_FLAG_KRATOS or resourceConsts.RESOURCE_FLAG_SON
    local includeFlags = {
      resourceConsts.RESOURCE_FLAG_PICKUP,
      characterResourceFlag,
      pickupSlotName
    }
    local resourcesByPickupSlot = GetResources(resourceConsts.WALLET_KRATOS, includeFlags, {}, sortingInfo, true)
    for _, pickupName in ipairs(resourcesByPickupSlot) do
      if 0 < GetAmount(pickupName) then
        tablex.FastInsert(pickupList, pickupName, itemIndex)
        itemIndex = itemIndex + 1
      end
    end
  end
  return pickupList
end
local AnyNewPickupsInSlotByCharacter = function(pickupSlotName, character)
  local pickups = GetPickupsInSlotByCharacter(pickupSlotName, character, nil)
  local anyNew = false
  for _, pickupName in ipairs(pickups) do
    if UI.HasNotification(consts.NotificationTypes.Resource, pickupName) then
      anyNew = true
      break
    end
  end
  return anyNew
end
local AnyNewPickupsByWeapon = function(pickupName)
  local character = pickupName == pickupConsts.SonBow and pickupConsts.TAG_PICKUP_SON or pickupConsts.TAG_PICKUP_KRATOS
  local pickupSlotName = pickupUtil.GetSlotName(pickupName)
  local anyNew = false
  if pickupUtil.IsValidSlotName(pickupSlotName) then
    local upgradeSlotNames = pickupSlotName == pickupConsts.Slot_ArmorShield and {
      pickupConsts.Slot_ArmorShield
    } or pickupUtil.GetWeaponUpgradeSlotNames(character, pickupSlotName)
    for _, upgradeSlot in ipairs(upgradeSlotNames) do
      if AnyNewPickupsInSlotByCharacter(upgradeSlot, character) then
        anyNew = true
        break
      end
    end
  end
  return anyNew
end
local WeaponMenu_GetSubStateNames = function()
  local subStateNames = {}
  for _, substateName in ipairs(consts.SUB_STATES.Weapon) do
    local isShieldSelection = substateName == pickupConsts.Shield
    if isShieldSelection then
      local completedCineNumber = game.Level.GetVariable("CompletedCineNumber")
      local mothersKnife = 20
      if completedCineNumber >= mothersKnife then
        local shieldList = GetPickupsInSlotByCharacter(pickupConsts.Slot_ArmorShield, pickupConsts.TAG_PICKUP_KRATOS)
        if shieldList ~= nil and 1 < #shieldList then
          tablex.FastInsert(subStateNames, substateName, #subStateNames + 1)
        end
      end
    else
      local isBladesSelection = substateName == pickupConsts.Blades
      local hasBlades = HasResource(pickupConsts.Blades)
      local isSonSelection = substateName == pickupConsts.SonBow
      if util.IsMenuSelectionAvailable(isBladesSelection, hasBlades, isSonSelection) then
        tablex.FastInsert(subStateNames, substateName, #subStateNames + 1)
      end
    end
  end
  return subStateNames
end
local WeaponMenu_AnyNewInside = function()
  local subStateNames = WeaponMenu_GetSubStateNames()
  local anyNew = false
  for _, subState in ipairs(subStateNames) do
    if AnyNewPickupsByWeapon(subState) then
      anyNew = true
      break
    end
  end
  return anyNew
end
local AnyNewArmorBySubState = function(subStateName)
  local character = subStateName == "StatsSon" and pickupConsts.TAG_PICKUP_SON or pickupConsts.TAG_PICKUP_KRATOS
  local pickupSlotNames = pickupUtil.GetAvailablePickupSlotNames(character)
  local anyNew = false
  for _, pickupSlot in ipairs(pickupSlotNames) do
    if AnyNewPickupsInSlotByCharacter(pickupSlot, character) then
      anyNew = true
      break
    end
  end
  return anyNew
end
local StatsMenu_GetSubStateNames = function()
  local subStateNames = {}
  for _, substateName in ipairs(consts.SUB_STATES.Stats) do
    local isBladesSelection = false
    local hasBlades = false
    local isSonSelection = substateName == "StatsSon"
    if util.IsMenuSelectionAvailable(isBladesSelection, hasBlades, isSonSelection) then
      tablex.FastInsert(subStateNames, substateName, #subStateNames + 1)
    end
  end
  return subStateNames
end
local StatsMenu_AnyNewInside = function()
  local subStateNames = StatsMenu_GetSubStateNames()
  local anyNew = false
  for _, subState in ipairs(subStateNames) do
    if AnyNewArmorBySubState(subState) then
      anyNew = true
      break
    end
  end
  return anyNew
end
local GetSortGroups = function(groupTypeFlag)
  local sortGroups = {}
  for groupIndex, group in ipairs(resourceConsts.SORTING_GROUPS[groupTypeFlag]) do
    local newItem = {}
    newItem.Name = resourceConsts.SORTING_GROUPS_NAMES[groupTypeFlag][groupIndex]
    newItem.Group = group
    tablex.FastInsert(sortGroups, newItem, #sortGroups + 1)
  end
  return sortGroups
end
local GetSortGroupFromMenu = function(currMenu)
  local sortListName = currMenu:get_sortListName()
  local sortList = currMenu:GetList(sortListName)
  local currItem = sortList:GetSelectedItem()
  if currItem ~= nil then
    return currItem.Group
  else
    return nil
  end
end
local GetSortGroupDisplayName = function(item)
  local lamsIndex = item.Name
  return util.GetLAMSMsg(lamsConsts[lamsIndex])
end
local GetSortGroupLabelDisplayText = function(item)
  local lamsIndex = item.Name
  return util.FormatLAMSString(lamsConsts.SortBy, util.GetLAMSMsg(lamsConsts[lamsIndex]))
end
return {
  IsValidResourceName = IsValidResourceName,
  HasFlag = HasFlag,
  GetDisplayName = GetDisplayName,
  GetDescription = GetDescription,
  GetIcon = GetIcon,
  GetRarity = GetRarity,
  GetRarityColor = GetRarityColor,
  GetAmount = GetAmount,
  GetMax = GetMax,
  IsResourceAPickup = IsResourceAPickup,
  IsResourceAGem = IsResourceAGem,
  IsTrinket = IsTrinket,
  AtLimit = AtLimit,
  HasResource = HasResource,
  ShouldUseLargeRow = ShouldUseLargeRow,
  ShouldUseItemCard = ShouldUseItemCard,
  IsNew = IsNew,
  ClearNew = ClearNew,
  DetermineIfCanCompare = DetermineIfCanCompare,
  GetSound = GetSound,
  GetArmorFlag = GetArmorFlag,
  GetEffectFlag = GetEffectFlag,
  GetMaterialSwapName = GetMaterialSwapName,
  GetIconText = GetIconText,
  GetResources = GetResources,
  GetPickupsInSlotByCharacter = GetPickupsInSlotByCharacter,
  AnyNewPickupsInSlotByCharacter = AnyNewPickupsInSlotByCharacter,
  AnyNewPickupsByWeapon = AnyNewPickupsByWeapon,
  WeaponMenu_GetSubStateNames = WeaponMenu_GetSubStateNames,
  WeaponMenu_AnyNewInside = WeaponMenu_AnyNewInside,
  AnyNewArmorBySubState = AnyNewArmorBySubState,
  StatsMenu_GetSubStateNames = StatsMenu_GetSubStateNames,
  StatsMenu_AnyNewInside = StatsMenu_AnyNewInside,
  GetSortGroups = GetSortGroups,
  GetSortGroupFromMenu = GetSortGroupFromMenu,
  GetSortGroupDisplayName = GetSortGroupDisplayName,
  GetSortGroupLabelDisplayText = GetSortGroupLabelDisplayText
}
