local LD = require("design.LevelDesignLibrary")
local TUT = require("game.GlobalTutorials")
local thisObj, thisLevel, interactZone, interactZone_Back, doorObj, keyType
local keyRunes = {}
local keys = {}
local runeSymbolNumbers = {
  RuneSymbol1 = 17,
  RuneSymbol2 = 21,
  RuneSymbol3 = 13
}
local playerInteractedFirstTime = false
local chestSealsBrokenEvent
local onBreakableDestroyed = {}
local challengeComplete = false
local keysUsed = 0
local runeTable = {}
local flipperBases = {}
local debug_toggle = false
function OnScriptLoaded(level, obj)
  thisObj = obj
  thisLevel = level
  doorObj = thisObj:FindSingleGOByName("spreadDoor")
  if doorObj.IsRefNode then
    doorObj = doorObj.Child
  end
  onBreakableDestroyed[1] = obj:GetLuaTableAttribute("Event_Breakable01Destroyed")
  onBreakableDestroyed[2] = obj:GetLuaTableAttribute("Event_Breakable02Destroyed")
  onBreakableDestroyed[3] = obj:GetLuaTableAttribute("Event_Breakable03Destroyed")
  chestSealsBrokenEvent = obj:GetLuaTableAttribute("chestSealsBrokenEvent")
  keyType = obj:GetLuaTableAttribute("KeyType")
  if chestSealsBrokenEvent then
    chestSealsBrokenEvent = LD.ExtractCallbacksForEvent(thisLevel, thisObj, chestSealsBrokenEvent)
  end
  if keyType == "MemoryChest" then
    runeSymbolNumbers = {}
  end
  for i = 1, 3 do
    if onBreakableDestroyed[i] then
      onBreakableDestroyed[i] = LD.ExtractCallbacksForEvent(level, obj, onBreakableDestroyed[i])
    end
    keys[i] = level:FindSingleGameObject(obj:FindLuaTableAttribute("sealBreakable0" .. tostring(i)))
    keyRunes["r" .. tostring(i) .. "a"] = obj:FindSingleGOByName("rune0" .. tostring(i) .. "a")
    keyRunes["r" .. tostring(i) .. "b"] = obj:FindSingleGOByName("rune0" .. tostring(i) .. "b")
    if keyType == "MemoryChest" then
      runeSymbolNumbers[i] = thisObj:FindLuaTableAttribute("SuccessRune_0" .. tostring(i))
    end
  end
  game.SubObject.Sleep(thisObj)
end
function OnPreStart(level, obj)
  if keys[1] and keys[2] and keys[3] then
    for i = 1, 3 do
      if keyType == "Bell" then
        local bellObj = keys[i]
        if bellObj.IsRefNode then
          bellObj = bellObj.Child
        end
        local runeType = bellObj:GetLuaTableAttribute("RuneType")
        if runeType == "None" then
          engine.Error("Bell Target '" .. bellObj:GetName() .. "' in level '" .. level.Name .. "' has RuneType set to 'None' for Runic Sealed Door '" .. thisObj.Parent:GetName() .. "' . " .. LD.GetParentTrace(bellObj) .. ")")
          break
        else
          keyRunes["r" .. tostring(i) .. "a"].LuaObjectScript.SelectRune(runeSymbolNumbers[runeType])
          keyRunes["r" .. tostring(i) .. "b"].LuaObjectScript.SelectRune(runeSymbolNumbers[runeType])
        end
        keys[i].LuaObjectScript.RegisterStartRingingCallback(function()
          OnBellStartRinging(i)
        end)
        keys[i].LuaObjectScript.RegisterStopRingingCallback(function()
          OnBellCooldownElapsed(i)
        end)
        if challengeComplete == false then
          EnableRunes(i)
        end
      elseif keyType == "Breakable" then
        keyRunes["r" .. tostring(i) .. "a"].LuaObjectScript.SelectRune(runeSymbolNumbers["RuneSymbol" .. tostring(i)])
        keyRunes["r" .. tostring(i) .. "b"].LuaObjectScript.SelectRune(runeSymbolNumbers["RuneSymbol" .. tostring(i)])
        keys[i].LuaObjectScript.OnBroken(function()
          KeyBroken(i)
        end)
      elseif keyType == "MemoryChest" then
        if keys[i].LuaObjectScript.RegisterOnRotateCallback == nil then
          engine.Error("GameObject '", thisObj.Parent:GetName(), "' has incorrect object name in Luatoolbox field FlipperBase_0", tostring(i), " [ ", keys[i]:GetName(), " ] is not a SpinnerChest Base module")
        end
        keyRunes["r" .. tostring(i) .. "a"].LuaObjectScript.SelectRune(runeSymbolNumbers[i])
        keyRunes["r" .. tostring(i) .. "b"].LuaObjectScript.SelectRune(runeSymbolNumbers[i])
        keys[i].LuaObjectScript.RegisterOnRotateCallback(OnRotateCallback)
      end
    end
  end
  if not challengeComplete then
    local jointName = "promptJoint"
    local jointIndex = doorObj:FindJointIndex(jointName)
    if jointIndex == nil then
      jointName = "promptJointFront"
      jointIndex = doorObj:FindJointIndex(jointName)
    end
    interactZone = LD.CreateInteractZone_Standard_180(doorObj, jointName)
    interactZone:SetHintAngle(180)
    interactZone:SetRequiresSonUnoccupied(true)
    interactZone_Back = LD.CreateInteractZone_Standard_180(doorObj, "promptJointBack")
    interactZone_Back:SetHintAngle(180)
    interactZone_Back:SetRequiresSonUnoccupied(true)
  end
end
function OnStart(level, obj)
  if keyType == "MemoryChest" then
    OnRotateCallback()
  end
end
function OnSaveCheckpoint(level, obj)
  return {challengeComplete = challengeComplete, keysUsed = keysUsed}
end
function OnRestoreCheckpoint(level, obj, savedInfo)
  challengeComplete = savedInfo.challengeComplete
  keysUsed = savedInfo.keysUsed
end
function OnUseWorld(level, obj)
  if interactZone and interactZone:PlayerCanInteract() or interactZone_Back and interactZone_Back:PlayerCanInteract() then
    local firstTime = game.Level.GetVariable("TUT_FirstRunicDoorTutorial")
    if firstTime == false then
      game.Level.SetVariable("TUT_FirstRunicDoorTutorial", true)
      TUT.RunicLock_FirstDoor_Tutorial()
    else
      LD.CallFunctionAfterDelay(function()
        TUT.RunicLock_Tutorial()
      end, 1)
    end
    interactZone:Lock()
    interactZone_Back:Lock()
  end
end
function EnableRunes(index)
  keyRunes["r" .. tostring(index) .. "a"].LuaObjectScript.Enable()
  keyRunes["r" .. tostring(index) .. "b"].LuaObjectScript.Enable()
end
function DisableRunes(index)
  keyRunes["r" .. tostring(index) .. "a"].LuaObjectScript.Disable()
  keyRunes["r" .. tostring(index) .. "b"].LuaObjectScript.Disable()
end
function OnChallengeComplete()
  challengeComplete = true
  local firstTime = game.Level.GetVariable("TUT_FirstRunicDoorTutorial")
  if firstTime == false then
    game.Level.SetVariable("TUT_FirstRunicDoorTutorial", true)
  end
  if chestSealsBrokenEvent then
    LD.ExecuteCallbacksForEvent(thisLevel, thisObj, chestSealsBrokenEvent, "chestSealsBrokenEvent")
  end
  interactZone:Disable()
  interactZone_Back:Disable()
  doorObj.LuaObjectScript.Unlock()
  doorObj.LuaObjectScript.Enable()
  if keyType == "Bell" then
    for i = 1, 3 do
      keys[i].LuaObjectScript.ChallengeComplete()
    end
  end
  if keyType ~= "MemoryChest" then
    LD.PlaySound(game.Player.FindPlayer():FindSingleSoundEmitterByName("SNDKratos"), "SND_LOOT_Chest_Runic_Puzzle_Complete")
  end
end
function KeyBroken(index)
  keysUsed = keysUsed + 1
  DisableRunes(index)
  game.Audio.PlaySound("SND_UX_Challenge_Progress")
  PlayMusicOnBroken()
  TUT.RunicProgress_Tutorial(keysUsed)
  if keysUsed == 3 and challengeComplete == false then
    OnChallengeComplete()
  end
  if onBreakableDestroyed[index] then
    LD.ExecuteCallbacksForEvent(thisLevel, thisObj, onBreakableDestroyed[index], "Brk 0" .. tostring(index) .. " Destroyed")
  end
end
function OnBellStartRinging(index)
  DisableRunes(index)
  keysUsed = keysUsed + 1
  if keysUsed == 3 and challengeComplete == false then
    OnChallengeComplete()
  end
end
function OnBellCooldownElapsed(index)
  if challengeComplete == false then
    keysUsed = keysUsed - 1
    EnableRunes(index)
  end
end
function OnRotateCallback()
  local newKeysUsed = 0
  local baseSuccess = {}
  keysUsed = 0
  if challengeComplete == true then
    return
  end
  for i = 1, 3 do
    baseSuccess[1] = runeSymbolNumbers[i] == keys[1].LuaObjectScript.GetCurrentRune()
    baseSuccess[2] = runeSymbolNumbers[i] == keys[2].LuaObjectScript.GetCurrentRune()
    baseSuccess[3] = runeSymbolNumbers[i] == keys[3].LuaObjectScript.GetCurrentRune()
    if baseSuccess[1] or baseSuccess[2] or baseSuccess[3] then
      DisableRunes(i)
      newKeysUsed = newKeysUsed + 1
    else
      EnableRunes(i)
    end
  end
  if keysUsed ~= newKeysUsed then
    keysUsed = newKeysUsed
  end
  if keysUsed == 3 and challengeComplete == false then
    OnChallengeComplete()
  end
end
function Debug_ToggleRunes()
  debug_toggle = not debug_toggle
  for index = 1, 3 do
    if debug_toggle then
      keyRunes["r" .. tostring(index) .. "a"].LuaObjectScript.Enable()
      keyRunes["r" .. tostring(index) .. "b"].LuaObjectScript.Enable()
    else
      keyRunes["r" .. tostring(index) .. "a"].LuaObjectScript.Disable()
      keyRunes["r" .. tostring(index) .. "b"].LuaObjectScript.Disable()
    end
  end
end
function DebugText()
  local color = require("core.color")
  local debugText = " keyType " .. keyType .. "\n"
  for i = 1, #keys do
    debugText = debugText .. keys[i]:GetName() .. " \n"
    debugText = debugText .. onBreakableDestroyed .. " \n"
  end
  engine.DrawTextInWorld(thisObj:GetWorldPosition() + engine.Vector.New(0, 1.5, 0), debugText, color.white)
end
local musicEvents = {isLooping = false, OnBroken = ""}
function MusicSetup(music)
  if music ~= nil then
    for key, value in pairs(musicEvents) do
      for newKey, newValue in pairs(music) do
        if newKey == key and newValue ~= nil and newValue ~= "" then
          musicEvents[key] = newValue
        end
      end
      LD.SoundDebug(tostring(key) .. ": " .. tostring(value))
    end
  end
end
function PlayMusicOnBroken()
  game.Audio.StartMusic(musicEvents.OnBroken)
end
