local uiCalls = require("ui.uicalls")
local TUT = require("game.GlobalTutorials")
local LD = require("design.LevelDesignLibrary")
local timers = require("level.timer")
local monitors = require("level.MonitorLibrary")
local thisObj, myMarker, combatScript
local goldChallenges = {
  currentID = 2,
  lastID = nil,
  types = {
    gauntlet = 0,
    time_attack = 1,
    no_damage = 2
  }
}
function OnScriptLoaded(level, obj)
  thisObj = obj
  myMarker = GameObjects.Muspelheim_Arena_Marker_06
  combatScript = GameObjects.CBT_Script_Msp160.LuaObjectScript
  game.SubObject.Sleep(obj)
end
function OnSaveCheckpoint(level, obj)
  return {goldChallenges = goldChallenges}
end
function OnRestoreCheckpoint(level, obj, savedInfo)
  goldChallenges = savedInfo.goldChallenges
end
function OnUpdate(level, obj)
  local currentEncounter = combatScript.GetChallengeEncounters()[goldChallenges.currentID]
  local encounterName = currentEncounter.Name
  if currentEncounter ~= nil and currentEncounter:IsRunning() then
    if goldChallenges[encounterName].updateFunction ~= nil then
      goldChallenges[encounterName].updateFunction()
    end
    local challengeType = goldChallenges[encounterName].challengeType
    local enemyCount, time
    if challengeType == 0 then
      enemyCount = currentEncounter:GetTotalSpawns() - currentEncounter:GetNumEnemiesKilled()
      goldChallenges[encounterName].elapsedTime = math.floor(goldChallenges[encounterName].elapsedTimer.time)
      local seconds = goldChallenges[encounterName].elapsedTime % 60
      local minutes = (goldChallenges[encounterName].elapsedTime - seconds) / 60
      time = string.format("%02d:%02d", minutes, seconds)
    elseif challengeType == 1 then
      enemyCount = goldChallenges[encounterName].last
      goldChallenges[encounterName].remainingTime = math.floor(goldChallenges[encounterName].total - goldChallenges[encounterName].remainingTimer.time)
      local seconds = goldChallenges[encounterName].remainingTime % 60
      local minutes = (goldChallenges[encounterName].remainingTime - seconds) / 60
      time = string.format("%02d:%02d", minutes, seconds)
    else
      enemyCount = goldChallenges[encounterName].last
    end
    local nextReward = GetNextScoreRewardString(currentEncounter)
    local rewardID = string.lower(nextReward)
    local targetScore = goldChallenges[encounterName][rewardID]
    TUT.Musp_ChallengeArena_Update(challengeType, GetNextScoreRewardString(currentEncounter), targetScore, enemyCount, time)
  else
    uiCalls.UI_Event_ClearAllDesignerMessages()
    uiCalls.DisableMechanicText()
    game.SubObject.Sleep(thisObj)
  end
end
function AllKeysAcquired()
  local totalKeys = TUT.Musp_GetNumKeys()
  if 3 <= totalKeys then
    return true
  end
  return false
end
function RemoveKeysOnComplete()
  local RemoveKey = function(keyName)
    local numKeys = game.Wallets.GetResourceValue("HERO", keyName)
    if 0 < numKeys then
      game.Wallets.RemoveResource("HERO", keyName, numKeys)
    end
  end
  RemoveKey("MspArenaKey01")
  RemoveKey("MspArenaKey02")
  RemoveKey("MspArenaKey03")
  RemoveKey("MspArenaKey04")
  RemoveKey("MspArenaKey05")
end
function GetAllChallengeInfo()
  return goldChallenges
end
function GetCurrentChallengeInfo()
  return goldChallenges[combatScript.GetChallengeEncounters()[goldChallenges.currentID].Name]
end
local nextID = 0
function SetupChallenge(encounter, args)
  nextID = nextID + 1
  local player = game.Player.FindPlayer()
  local challengeEncounters = combatScript.GetChallengeEncounters()
  challengeEncounters[#challengeEncounters + 1] = encounter
  local encounterName = encounter.Name
  if goldChallenges[encounterName] == nil then
    goldChallenges[encounterName] = {}
  end
  local nextEncounterEntry = goldChallenges[encounterName]
  if nextEncounterEntry.last == nil then
    if args.challengeType == goldChallenges.types.gauntlet then
      nextEncounterEntry.last = "0:00"
    else
      nextEncounterEntry.last = 0
    end
  end
  if nextEncounterEntry.best == nil then
    if args.challengeType == goldChallenges.types.gauntlet then
      nextEncounterEntry.best = "0:00"
    else
      nextEncounterEntry.best = 0
    end
  end
  nextEncounterEntry.challengeType = args.challengeType
  nextEncounterEntry.bronze = args.bronze
  nextEncounterEntry.silver = args.silver
  nextEncounterEntry.gold = args.gold
  nextEncounterEntry.id = nextID
  nextEncounterEntry.loadGroup = args.loadGroup
  encounter:OnStart(function()
    game.SubObject.Wake(thisObj)
    if args.challengeType == goldChallenges.types.gauntlet then
      nextEncounterEntry.last = "0:00"
    else
      nextEncounterEntry.last = 0
    end
  end)
  encounter:OnCombatStart(function()
    game.Audio.StartMusic("SND_MX_MSP_trial_36_start")
  end)
  if nextEncounterEntry.challengeType == goldChallenges.types.gauntlet then
    encounter:OnStart(function()
      nextEncounterEntry.elapsedTimer = timers.StartLevelTimer(99999)
      nextEncounterEntry.elapsedTime = 0
    end)
    encounter:OnComplete(function()
      nextEncounterEntry.last = GetFormattedTime(nextEncounterEntry.elapsedTimer.time)
      UpdateCounts(encounterName)
      nextEncounterEntry.elapsedTimer:Stop()
      nextEncounterEntry.elapsedTimer = nil
    end)
  elseif nextEncounterEntry.challengeType == goldChallenges.types.time_attack then
    nextEncounterEntry.pickup = "MuspelheimPreventPlayerDamage"
    encounter:OnEnemyDeath(function()
      nextEncounterEntry.last = nextEncounterEntry.last + 1
    end)
    local challengeTime
    challengeTime = ConvertStringToTime(args.timeLimit)
    encounter:OnStart(function()
      nextEncounterEntry.total = challengeTime
      nextEncounterEntry.remainingTime = challengeTime
      nextEncounterEntry.remainingTimer = timers.StartLevelTimer(challengeTime, function()
        TimeElapsed(encounter)
      end)
    end)
    encounter:OnComplete(function()
      if nextEncounterEntry.remainingTimer ~= nil then
        nextEncounterEntry.remainingTimer:Stop()
        nextEncounterEntry.remainingTimer = nil
      end
    end)
  elseif nextEncounterEntry.challengeType == goldChallenges.types.no_damage then
    nextEncounterEntry.pickup = "MuspelheimSingleHitChallenge"
    encounter:OnEnemyDeath(function()
      nextEncounterEntry.last = nextEncounterEntry.last + 1
    end)
    encounter:OnStart(function()
      _G.AcquirePickup("MuspelheimSingleHitChallenge")
      function nextEncounterEntry.updateFunction()
        if player:PickupIsAcquired("MuspelheimSingleHitChallenge") == false then
          _G.RelinquishPickup("MuspelheimSingleHitChallenge")
          ChallengeFailed(encounter)
        end
      end
    end)
    encounter:OnComplete(function()
      _G.RelinquishPickup("MuspelheimSingleHitChallenge")
    end)
  end
  if nextEncounterEntry.pickup ~= nil then
    encounter:OnStart(function()
      _G.AcquirePickup(nextEncounterEntry.pickup)
    end)
  end
  encounter:OnComplete(function()
    game.SubObject.Sleep(thisObj)
    ChallengeComplete(encounter)
  end)
end
function CheckSuccessCriteria(encounter)
  local encounterName = encounter.Name
  local challengeType = goldChallenges[encounterName].challengeType
  if challengeType == goldChallenges.types.gauntlet then
    return ConvertStringToTime(goldChallenges[encounterName].last) <= ConvertStringToTime(goldChallenges[encounterName].bronze)
  else
    return goldChallenges[encounterName].last >= goldChallenges[encounterName].bronze
  end
end
function ChallengeComplete(encounter)
  local encounterName = encounter.Name
  myMarker.LuaObjectScript.UpdateRewards(GetFinalScoreRewardString(encounter))
  myMarker.LuaObjectScript.OnArenaComplete(LD.GetEntityVariable("MUS_Arena6Rank") + 1)
  myMarker.LuaObjectScript.IncrementArenaTrackingVar()
  UpdateChallenge()
  if goldChallenges[encounterName].pickup ~= nil then
    _G.RelinquishPickup(goldChallenges[encounter.Name].pickup)
  end
  UpdateCounts(encounterName)
  uiCalls.DisableMechanicText()
  uiCalls.UI_Event_ClearAllDesignerMessages()
  LD.CallFunctionAfterDelay(function()
    TUT.Musp_ChallengeArena_Complete(goldChallenges[encounter.Name].challengeType, GetFinalScoreRewardString(encounter), goldChallenges[encounter.Name].last)
  end, 0.5)
  game.Audio.StartMusic("SND_MX_MSP_trial_36_win")
  game.World.StoreCheckpoint()
end
function ChallengeFailed(encounter)
  _G.MSP_Despawn_Enemy_VFX(encounter)
  encounter:Reset()
  if goldChallenges[encounter.Name].pickup ~= nil then
    _G.RelinquishPickup(goldChallenges[encounter.Name].pickup)
  end
  if CheckSuccessCriteria(encounter) then
    ChallengeComplete(encounter)
  else
    uiCalls.DisableMechanicText()
    LD.CallFunctionAfterDelay(function()
      uiCalls.SendBottomDesignerMessage({Text = 37911})
    end, 1)
    myMarker.LuaObjectScript.ChallengeFailed()
    game.Audio.StartMusic("SND_MX_MSP_trial_36_fail")
  end
  UpdateCounts(encounter.Name)
end
function UpdateChallenge()
  goldChallenges.currentID = goldChallenges.currentID + 1
  if goldChallenges.currentID > #combatScript.GetChallengeEncounters() then
    goldChallenges.currentID = 1
  end
end
function TimeElapsed(encounter)
  local name = encounter.Name
  if goldChallenges[name].remainingTimer ~= nil then
    goldChallenges[name].remainingTimer:Stop()
    goldChallenges[name].remainingTimer = nil
  end
  ChallengeFailed(encounter)
end
function GetFinalScoreRewardString(encounter)
  local encounterName = encounter.Name
  local lastScore = goldChallenges[encounter.Name].last
  local challengeType = goldChallenges[encounter.Name].challengeType
  local tier
  if challengeType == goldChallenges.types.gauntlet then
    lastScore = ConvertStringToTime(lastScore)
    if lastScore <= ConvertStringToTime(goldChallenges[encounterName].gold) then
      tier = "Gold"
    elseif lastScore <= ConvertStringToTime(goldChallenges[encounterName].silver) then
      tier = "Silver"
    else
      tier = "Bronze"
    end
  elseif lastScore >= goldChallenges[encounterName].gold then
    tier = "Gold"
  elseif lastScore >= goldChallenges[encounterName].silver then
    tier = "Silver"
  elseif lastScore >= goldChallenges[encounterName].bronze then
    tier = "Bronze"
  else
    tier = "NONE"
  end
  return tier
end
function UpdateCounts(encounterName)
  local challengeType = goldChallenges[encounterName].challengeType
  if challengeType == goldChallenges.types.gauntlet then
    if goldChallenges[encounterName].best == "0:00" then
      goldChallenges[encounterName].best = goldChallenges[encounterName].last
    end
    if ConvertStringToTime(goldChallenges[encounterName].last) < ConvertStringToTime(goldChallenges[encounterName].best) then
      goldChallenges[encounterName].best = goldChallenges[encounterName].last
    end
  elseif goldChallenges[encounterName].last > goldChallenges[encounterName].best then
    goldChallenges[encounterName].best = goldChallenges[encounterName].last
  end
end
function GetNextScoreRewardString(encounter)
  local encounterName = encounter.Name
  local lastScore = goldChallenges[encounter.Name].last
  local challengeType = goldChallenges[encounter.Name].challengeType
  if challengeType == goldChallenges.types.gauntlet then
    local last = goldChallenges[encounterName].elapsedTimer.time
    if last < ConvertStringToTime(goldChallenges[encounterName].gold) then
      return "Gold"
    elseif last < ConvertStringToTime(goldChallenges[encounterName].silver) then
      return "Silver"
    else
      return "Bronze"
    end
  elseif lastScore < goldChallenges[encounterName].bronze then
    return "Bronze"
  elseif lastScore < goldChallenges[encounterName].silver then
    return "Silver"
  else
    return "Gold"
  end
end
function ConvertStringToTime(time_string)
  local colonIndex = string.find(time_string, ":")
  if colonIndex ~= nil then
    local minutes = tonumber(string.sub(time_string, 1, colonIndex - 1))
    local seconds = tonumber(string.sub(time_string, colonIndex + 1))
    return minutes * 60 + seconds
  else
    return tonumber(time_string) * 60
  end
end
function GetFormattedTime(time)
  local seconds = time % 60
  local minutes = (time - seconds) / 60
  return string.format("%02d:%02d", minutes, seconds)
end
