local tablex = require("core.tablex")
local colors = require("ui.colors")
local lamsConsts = require("ui.lamsConsts")
local mapConsts = require("ui.mapConsts")
local util = require("ui.util")
local Camera = game.Camera
local Level = game.Level
local Map = game.Map
local UI = game.UI
local GetRealmNameByGlobalLevelRealmIndex = function(realmIndex)
  local realmName = mapConsts.REALM_MIDGARD
  if realmIndex ~= nil then
    realmName = mapConsts.REALM_NAMES_BY_GLOBAL_LEVEL_REALM_INDEX[realmIndex]
  end
  return realmName
end
local GetPlayerRealm = function()
  local currentPlayerRealmIndex = Level.GetVariable("_GBL_CurrentRealm")
  return GetRealmNameByGlobalLevelRealmIndex(currentPlayerRealmIndex)
end
local GetRealmCollisionGOName = function(realmName)
  return realmName .. "_collision"
end
local FindIconInfo = function(collisionGO)
  local info = Map.FindInfoFromIcon(collisionGO)
  return info ~= nil, info
end
local IsPlayerIcon = function(collisionGO)
  return collisionGO:GetName() == "mapiconplayer"
end
local GetPrioritizedIconAndTerrain = function(collisionGOs)
  local bestIcon, bestTerrain
  if type(collisionGOs) == "table" then
    local highestPriority = 0
    for _, collGO in ipairs(collisionGOs) do
      local isMapIcon, iconInfo = FindIconInfo(collGO)
      if isMapIcon == true then
        if bestIcon == nil or highestPriority < iconInfo.Priority then
          highestPriority = iconInfo.Priority
          bestIcon = {}
          bestIcon.GO = collGO
          bestIcon.Type = mapConsts.MAP_COLL_ICON
          bestIcon.Info = iconInfo
        end
      elseif IsPlayerIcon(collGO) then
        highestPriority = -1
        if bestIcon == nil or iconInfo ~= nil and highestPriority < iconInfo.Priority then
          bestIcon = {}
          bestIcon.GO = collGO
          bestIcon.Type = mapConsts.MAP_COLL_PLAYER_ICON
        end
      elseif bestTerrain == nil then
        bestTerrain = {}
        bestTerrain.GO = collGO
        bestTerrain.Type = mapConsts.MAP_COLL_TERRAIN
      end
    end
  end
  return bestIcon, bestTerrain
end
local GetMapCollisionInfoGameObject = function(collisionInfo)
  assert(collisionInfo ~= nil, "GetCollisionInfoGameObject called with no collision info!")
  return collisionInfo.GO
end
local GetMapCollisionInfoType = function(collisionInfo)
  assert(collisionInfo ~= nil, "GetMapCollisionInfoType called with no collision info!")
  return collisionInfo.Type
end
local GetMapCollisionInfoInfo = function(collisionInfo)
  assert(collisionInfo ~= nil, "GetMapCollisionInfoInfo called with no collision info!")
  return collisionInfo.Info
end
local GetTempleRotationFrame = function(realmName)
  assert(mapConsts.TEMPLE_ROTATION_FRAME[realmName] ~= nil, "Rotation frame does not exist for " .. tostring(realmName))
  return mapConsts.TEMPLE_ROTATION_FRAME[realmName]
end
local UpdateTempleRotation = function(realmName)
  local goTemple = util.GetUiObjByName("CalderaTemple")
  assert(goTemple ~= nil, "UpdateTempleRotation could not find CalderaTemple!")
  if realmName == mapConsts.REALM_MIDGARD then
    local iSelectedRealm = Level.GetVariable("_GBL_BridgePosition")
    realmName = GetRealmNameByGlobalLevelRealmIndex(iSelectedRealm)
  end
  local rotationAnimFrame = GetTempleRotationFrame(realmName)
  UI.Anim(goTemple, 0, "", 0, rotationAnimFrame)
end
local GetRegionInfo = function(regionID)
  assert(regionID ~= nil, "GetRegionInfo called with no ID!")
  return Map.GetRegionInfo(regionID)
end
local RegionInfo_GetID = function(regionInfo)
  assert(regionInfo ~= nil, "RegionInfo_GetID called with no region info!")
  return regionInfo.Id
end
local RegionInfo_GetState = function(regionInfo)
  assert(regionInfo ~= nil, "RegionInfo_GetState called with no region info!")
  return regionInfo.State
end
local RegionInfo_GetNameLamsID = function(regionInfo)
  assert(regionInfo ~= nil, "RegionInfo_GetNameLamsID called with no region info!")
  return regionInfo.LamsNameId
end
local RegionInfo_GetDescriptionLamsID = function(regionInfo)
  assert(regionInfo ~= nil, "RegionInfo_GetDescriptionLamsID called with no region info!")
  return regionInfo.LamsDescriptionId
end
local RegionInfo_GetPowerLevel = function(regionInfo)
  assert(regionInfo ~= nil, "RegionInfo_GetPowerLevel called with no region info!")
  return regionInfo.PowerLevel
end
local RegionInfo_GetName = function(regionInfo)
  assert(regionInfo ~= nil, "RegionInfo_GetName called with no region info!")
  local regionID = RegionInfo_GetID(regionInfo)
  local hashAsStr = tostring(regionID)
  return mapConsts.REGION_NAME_HASH_TO_STRING[hashAsStr]
end
local RegionInfo_GetDisplayName = function(regionInfo)
  assert(regionInfo ~= nil, "nil info table passed into RegionInfo_GetDisplayName!")
  local displayName
  displayName = util.GetLAMSMsg(RegionInfo_GetNameLamsID(regionInfo), RegionInfo_GetID(regionInfo))
  return displayName
end
local RegionInfo_GetDescription = function(regionInfo)
  assert(regionInfo ~= nil, "nil info table passed into RegionInfo_GetDescription!")
  return util.GetLAMSMsg(RegionInfo_GetDescriptionLamsID(regionInfo), RegionInfo_GetID(regionInfo))
end
local RegionInfo_IsDiscovered = function(regionInfo)
  assert(regionInfo ~= nil, "nil regionInfo passed into IsRegionDiscovered!")
  assert(type(regionInfo) == "table", "regionInfo passed into IsRegionDiscovered was not a table!")
  return regionInfo.State == tweaks.eTokenState.kDiscovered or regionInfo.State == tweaks.eTokenState.kDiscoveredButLocked
end
local RegionInfo_GetRegionInfoFromWadName = function(wadName)
  if not util.IsStringNilOrEmpty(wadName) then
    local regionFound, regionID = Map.FindRegionInfoFromWad(wadName)
    if regionFound then
      return GetRegionInfo(regionID)
    end
  end
  return nil
end
local Region_HasFlags = function(regionID, flagTable)
  assert(regionID ~= nil, "Region_HasFlags called with no ID!")
  return Map.RegionHasFlag(regionID, flagTable)
end
local Region_SetState = function(regionID, state)
  assert(regionID ~= nil, "Region_SetState called with no ID!")
  Map.ChangeRegionState(regionID, state)
end
local IsRealmDiscovered = function(realmHash)
  local isDiscovered = false
  local realmsTable = Map.GetRealmsInfoTable()
  local realmFound = false
  for _, realm in ipairs(realmsTable) do
    if realm.Id == realmHash then
      isDiscovered = realm.State == tweaks.eTokenState.kDiscovered or realm.State == tweaks.eTokenState.kDiscoveredButLocked
      realmFound = true
      break
    end
  end
  assert(realmFound == true, "Realm was not found when checking for locked state")
  return isDiscovered
end
local IsRealmLocked = function(realmHash)
  local isLocked = false
  local realmsTable = Map.GetRealmsInfoTable()
  local realmFound = false
  for _, realm in ipairs(realmsTable) do
    if realm.Id == realmHash then
      isLocked = realm.State == tweaks.eTokenState.kDiscoveredButLocked
      realmFound = true
      break
    end
  end
  assert(realmFound == true, "Realm was not found when checking for locked state")
  return isLocked
end
local GetRealmNames = function()
  return mapConsts.REALM_NAMES
end
local GetRealmNameHashes = function()
  local realmsTable = Map.GetRealmsInfoTable()
  local realmNamesHashTable = {}
  local fastTravelRealmHash = engine.Hash(mapConsts.REALM_FASTTRAVEL)
  for key, realm in ipairs(realmsTable) do
    if realm.Id ~= fastTravelRealmHash then
      realmNamesHashTable[key] = realm.Id
    end
  end
  return realmNamesHashTable
end
local GetRealmNameFromHash = function(realmNameHash)
  local realmName
  for _, currentRealmName in pairs(mapConsts.REALM_NAMES) do
    if realmNameHash == engine.Hash(currentRealmName) then
      realmName = currentRealmName
      break
    end
  end
  return realmName
end
local GetRealmNameFromRegionHash = function(regionNameHash)
  local foundRealm = false
  local realmNameHash, realmName
  foundRealm, realmNameHash = Map.FindRealmFromRegion(regionNameHash)
  if foundRealm == true then
    realmName = GetRealmNameFromHash(realmNameHash)
  end
  return realmName
end
local GetDiscoveredRealmNames = function()
  local discoveredRealms = {}
  local allRealms = GetRealmNameHashes()
  for _, realmNameHash in ipairs(allRealms) do
    if IsRealmDiscovered(realmNameHash) then
      tablex.FastInsert(discoveredRealms, GetRealmNameFromHash(realmNameHash), #discoveredRealms + 1)
    end
  end
  return discoveredRealms
end
local GetAllRegionInfoInRealm = function(realmName)
  local regions = {}
  if not util.IsStringNilOrEmpty(realmName) then
    regions = Map.GetRegionsInfoTable(realmName)
  end
  return regions
end
local GetRealmLAMSNameFromHash = function(hashId)
  local realmsTable = Map.GetRealmsInfoTable()
  local LAMsId
  for _, realm in ipairs(realmsTable) do
    if realm.Id == hashId then
      LAMsId = realm.LamsNameId
      break
    end
  end
  return LAMsId
end
local GetRealmColor = function(realmName)
  local color = colors.WHITE
  if IsRealmLocked(realmName) == true then
    color = colors.GRAY
  end
  return color
end
local GetMapMarkerInfo = function(markerIDHash)
  assert(markerIDHash ~= nil, "nil marker ID hash passed into GetMapMarkerInfo!")
  return Map.GetMarkerInfo(markerIDHash)
end
local GetMapMarkerInfoID = function(markerInfo)
  assert(markerInfo ~= nil, "nil info table passed into GetMapMarkerInfoID!")
  return markerInfo.Id
end
local MapMarkerInfoHasStates = function(markerInfo, stateTable)
  assert(markerInfo ~= nil, "nil info table passed into MapMarkerInfoHasStates!")
  local hasState = false
  if #stateTable == 0 then
    hasState = true
  else
    local currState = markerInfo.State
    for _, state in ipairs(stateTable) do
      if currState == state then
        hasState = true
        break
      end
    end
  end
  return hasState
end
local MapMarker_GetRegion = function(markerIDHash)
  local regionFound = false
  local regionNameHash
  regionFound, regionNameHash = Map.FindRegionFromMarker(markerIDHash)
  return regionFound, regionNameHash
end
local MapMarker_GetRealmName = function(markerIDHash)
  local realmName
  local regionFound, regionNameHash = MapMarker_GetRegion(markerIDHash)
  if regionFound == true then
    realmName = GetRealmNameFromRegionHash(regionNameHash)
  end
  return realmName
end
return {
  GetPlayerRealm = GetPlayerRealm,
  GetRealmCollisionGOName = GetRealmCollisionGOName,
  FindIconInfo = FindIconInfo,
  GetPrioritizedIconAndTerrain = GetPrioritizedIconAndTerrain,
  GetMapCollisionInfoGameObject = GetMapCollisionInfoGameObject,
  GetMapCollisionInfoType = GetMapCollisionInfoType,
  GetMapCollisionInfoInfo = GetMapCollisionInfoInfo,
  UpdateTempleRotation = UpdateTempleRotation,
  GetRegionInfo = GetRegionInfo,
  RegionInfo_GetID = RegionInfo_GetID,
  RegionInfo_GetState = RegionInfo_GetState,
  RegionInfo_GetNameLamsID = RegionInfo_GetNameLamsID,
  RegionInfo_GetDescriptionLamsID = RegionInfo_GetDescriptionLamsID,
  RegionInfo_GetPowerLevel = RegionInfo_GetPowerLevel,
  RegionInfo_GetName = RegionInfo_GetName,
  RegionInfo_GetDisplayName = RegionInfo_GetDisplayName,
  RegionInfo_GetDescription = RegionInfo_GetDescription,
  RegionInfo_IsDiscovered = RegionInfo_IsDiscovered,
  RegionInfo_GetRegionInfoFromWadName = RegionInfo_GetRegionInfoFromWadName,
  Region_HasFlags = Region_HasFlags,
  Region_SetState = Region_SetState,
  IsRealmDiscovered = IsRealmDiscovered,
  IsRealmLocked = IsRealmLocked,
  GetRealmNames = GetRealmNames,
  GetRealmNameFromHash = GetRealmNameFromHash,
  GetRealmNameFromRegionHash = GetRealmNameFromRegionHash,
  GetRealmNameHashes = GetRealmNameHashes,
  GetDiscoveredRealmNames = GetDiscoveredRealmNames,
  GetAllRegionInfoInRealm = GetAllRegionInfoInRealm,
  GetRealmColor = GetRealmColor,
  GetRealmLAMSNameFromHash = GetRealmLAMSNameFromHash,
  GetMapMarkerInfo = GetMapMarkerInfo,
  GetMapMarkerInfoID = GetMapMarkerInfoID,
  MapMarkerInfoHasStates = MapMarkerInfoHasStates,
  MapMarker_GetRegion = MapMarker_GetRegion,
  MapMarker_GetRealmName = MapMarker_GetRealmName
}
