local LD = require("design.LevelDesignLibrary")
local ND = require("design.NarrativeDesignLibrary")
local timer = require("level.timer")
local thisObj, thisLevel, player, son, banterName, loopingDelay, typeOfLoop, moveName, targetMovePercent, playAtSpecificPercent, creatureChoice, loopingSeq, creature
local enabled = false
local firstLoop = true
local loopCounter = 0
function OnScriptLoaded(level, obj)
  thisObj = obj
  thisLevel = level
  player = game.Player.FindPlayer()
  son = game.AI.FindSon()
  banterName = thisObj:GetLuaTableAttribute("BanterName")
  loopingDelay = thisObj:GetLuaTableAttribute("LoopingDelay")
  typeOfLoop = thisObj:GetLuaTableAttribute("TypeOfLoop")
  creatureChoice = thisObj:GetLuaTableAttribute("CreatureChoice")
  moveName = thisObj:GetLuaTableAttribute("MoveName")
  playAtSpecificPercent = thisObj:GetLuaTableAttribute("PlayAtSpecificPercent")
  targetMovePercent = thisObj:GetLuaTableAttribute("TargetMovePercent")
  if not banterName then
    engine.Error("Banter Module '", thisObj.Parent:GetName(), "' in level '", thisLevel.Name, "' is RECEIVING NIL for BanterName. Something is wrong with the Maya Lua Table or the LD library. (", LD.GetParentTrace(thisObj), ")")
  end
  if not loopingDelay then
    engine.Error("Banter Module '", thisObj.Parent:GetName(), "' in level '", thisLevel.Name, "' is RECEIVING NIL for LoopingDelay. Something is wrong with the Maya Lua Table or the LD library. (", LD.GetParentTrace(thisObj), ")")
  end
  if not typeOfLoop then
    engine.Error("Banter Module '", thisObj.Parent:GetName(), "' in level '", thisLevel.Name, "' is RECEIVING NIL for TypeOfLoop. Something is wrong with the Maya Lua Table or the LD library. (", LD.GetParentTrace(thisObj), ")")
  end
  if not creatureChoice then
    engine.Error("Banter Module '", thisObj.Parent:GetName(), "' in level '", thisLevel.Name, "' is RECEIVING NIL for CreatureChoice. Something is wrong with the Maya Lua Table or the LD library. (", LD.GetParentTrace(thisObj), ")")
  end
  if not moveName then
    engine.Error("Banter Module '", thisObj.Parent:GetName(), "' in level '", thisLevel.Name, "' is RECEIVING NIL for MoveName. Something is wrong with the Maya Lua Table or the LD library. (", LD.GetParentTrace(thisObj), ")")
  end
  if not targetMovePercent then
    engine.Error("Banter Module '", thisObj.Parent:GetName(), "' in level '", thisLevel.Name, "' is RECEIVING NIL for TargetMovePercent. Something is wrong with the Maya Lua Table or the LD library. (", LD.GetParentTrace(thisObj), ")")
  end
  if creatureChoice == "" then
    engine.Error("Banter Module '", thisObj.Parent:GetName(), "' in level '", thisLevel.Name, "' has an empty string for CreatureChoice. This is not allowed; if no creature is intended, choose 'None' instead. (", LD.GetParentTrace(thisObj), ")")
  end
  if banterName == "" then
    engine.Error("Banter Loop Error 1: Module '", thisObj.Parent:GetName(), "' in level '", thisLevel.Name, "' does not have any banter to play.  Either add the appropriate banter or delete this refnode. (", LD.GetParentTrace(thisObj), ")")
  end
  if loopingDelay < 1 or loopingDelay == 0 then
    loopingDelay = 1
    engine.Warning("Banter Loop Error 2: Module '" .. thisObj.Parent:GetName() .. "' in level '" .. thisLevel.Name .. "' needs a LoopingDelay integer to know how often to trigger its banter line. Zero is invalid. Now changing this variable to 1 to avoid a crash. (" .. LD.GetParentTrace(thisObj) .. ")")
  end
  if typeOfLoop == "Count Seconds" and (moveName ~= "" or creatureChoice ~= "None" or not not playAtSpecificPercent) then
    engine.Error("Banter Loop Error 3: Module '" .. thisObj.Parent:GetName() .. "' in level '" .. thisLevel.Name .. "' has been given a moveName or creatureChoice or playAtSpecificPercent but is set to Count Seconds mode. It will not account for any of those variables. (" .. LD.GetParentTrace(thisObj) .. "). TypeOfLoop is " .. typeOfLoop .. " and moveName is " .. moveName .. " and creatureChoice is " .. creatureChoice .. " and playAtSpecificPercent is " .. tostring(playAtSpecificPercent))
  end
  if typeOfLoop == "Count Idle Loops" and (moveName == "" or creatureChoice == "None") then
    engine.Error("Banter Loop Error 4: Module '" .. thisObj.Parent:GetName() .. "' in level '" .. thisLevel.Name .. "' is set to Count Idle Loops, but is missing a moveName or creatureChoice. It cannot loop the banter without a move name AND a creature choice (" .. LD.GetParentTrace(thisObj) .. ")")
  end
  if not playAtSpecificPercent and 0 < targetMovePercent then
    engine.Error("Banter Loop Error 5: Module '" .. thisObj.Parent:GetName() .. "' in level '" .. thisLevel.Name .. "' has been given a targetMovePercent even though playAtSpecificPercent is not checked (" .. LD.GetParentTrace(thisObj) .. ")")
  end
  game.SubObject.Sleep(thisObj)
end
function OnSaveCheckpoint(level, obj)
  local savedInfo = {}
  savedInfo.enabled = enabled
  savedInfo.loopCounter = loopCounter
  savedInfo.creature = creature
  savedInfo.targetMovePercent = targetMovePercent
  return savedInfo
end
function OnRestoreCheckpoint(level, obj, savedInfo)
  enabled = savedInfo.enabled
  loopCounter = savedInfo.loopCounter
  creature = savedInfo.creature
  targetMovePercent = savedInfo.targetMovePercent
  if enabled then
    timer.StartLevelTimer(loopingDelay, StartLoop)
  end
end
function Enable()
  if not enabled then
    enabled = true
    StartLoop()
  else
    engine.Warning("Banter Module '" .. thisObj.Parent:GetName() .. "' in level '" .. thisLevel.Name .. "' Caution, the Enable function is being called when the module is already enabled. (" .. LD.GetParentTrace(thisObj) .. ")")
  end
end
function Disable()
  enabled = false
  if loopingSeq then
    loopingSeq:Complete()
    loopingSeq = nil
  end
end
function StartLoop()
  if typeOfLoop == "Count Seconds" then
    DoTimerBanterLoop()
  elseif typeOfLoop == "Count Idle Loops" then
    GetCreatureAndStartLooping()
  end
end
function DoTimerBanterLoop()
  if enabled then
    local banterLoopName = banterName .. " timerBanterLoop"
    loopingSeq = nil
    loopingSeq = LD.CreateCineSequence(thisLevel, thisObj, banterLoopName)
    loopingSeq:Do(function()
      game.Audio.PlayBanter(banterName)
    end)
    loopingSeq:WaitSeconds(loopingDelay)
    loopingSeq:Do(function()
      loopingSeq = nil
    end)
    loopingSeq:Do(DoTimerBanterLoop)
    loopingSeq:StartSequence()
  end
end
function GetCreatureAndStartLooping()
  if creatureChoice == "Son" then
    creature = son
    DoMoveDetectionBanterLoop()
  elseif creatureChoice == "Player" then
    creature = player
    DoMoveDetectionBanterLoop()
  elseif creatureChoice == "Freya" then
    local waitForFreyaSeq = LD.CreateCineSequence(thisLevel, thisObj, "setFreyaAsBanterLoopCreature")
    waitForFreyaSeq:WaitForFunctionTrue(DoesFreyaExist)
    waitForFreyaSeq:Do(function()
      creature = ND.FindFreya()
    end)
    waitForFreyaSeq:Do(function()
      DoMoveDetectionBanterLoop()
    end)
    waitForFreyaSeq:StartSequence()
  else
    creature = thisLevel:FindSingleGameObject(creatureChoice)
    CreatureReferenceErrorCheck()
    DoMoveDetectionBanterLoop()
  end
end
function CreatureReferenceErrorCheck()
  if not creature then
    engine.Error("Banter Loop Module '" .. thisObj.Parent:GetName() .. "' in level '" .. thisLevel.Name .. "' could not find an object to match the corresponding creature choice, '" .. creatureChoice .. "'. IT must be the object name of the creature. Make sure it does not begin with 'go' unless that is in the creaute's name. For example, use 'brok00' instead of 'gobrok00' (" .. LD.GetParentTrace(thisObj) .. ")")
  end
  creature = creature:GetCreature()
  if not creature then
    engine.Error("Banter Loop Module '" .. thisObj.Parent:GetName() .. "' in level '" .. thisLevel.Name .. "' found an object that matched the creature choice (" .. tostring(thisLevel:FindSingleGameObject(creatureChoice)) .. "), but it contained no creature (" .. LD.GetParentTrace(thisObj) .. ")")
  end
end
function DoesFreyaExist()
  local freyaAiObject
  freyaAiObject = ND.CatchFreyaReference(freyaAiObject)
  if freyaAiObject ~= nil then
    return true
  else
    return false
  end
end
function DoMoveDetectionBanterLoop()
  if enabled then
    local banterLoopName = banterName .. " move-based banterLoop"
    loopingSeq = nil
    loopingSeq = LD.CreateCineSequence(thisLevel, thisObj, banterLoopName)
    if firstLoop then
      loopingSeq:WaitForFunctionTrue(IsCreaturePlayingMove)
      firstLoop = false
      if playAtSpecificPercent and creature:GetActiveMovePercent() <= targetMovePercent then
        loopingSeq:WaitForFunctionTrue(IsMoveAtTargetPercent)
        loopingSeq:Do(PlayBanter)
      elseif not playAtSpecificPercent then
        loopingSeq:Do(PlayBanter)
        loopingSeq:Do(function()
          targetMovePercent = creature:GetActiveMovePercent()
        end)
      end
    end
    local prevMovePercent
    loopingSeq:WaitForFunctionTrue(function()
      local result = false
      local currentMovePercent = creature:GetActiveMovePercent()
      if prevMovePercent and currentMovePercent < prevMovePercent then
        result = true
      end
      prevMovePercent = currentMovePercent
      return result
    end)
    loopingSeq:WaitForFunctionTrue(IsCreaturePlayingMove)
    loopingSeq:WaitForFunctionTrue(IsMoveAtTargetPercent)
    loopingSeq:Do(CheckIfBanterShouldPlay)
    loopingSeq:Do(function()
      loopingSeq = nil
    end)
    loopingSeq:Do(DoMoveDetectionBanterLoop)
    loopingSeq:StartSequence()
  end
end
function IsCreaturePlayingMove()
  return creature:IsPlayingMove(moveName)
end
function IsMoveAtTargetPercent()
  return creature:GetActiveMovePercent() > targetMovePercent
end
function CheckIfBanterShouldPlay()
  loopCounter = loopCounter + 1
  if loopCounter >= loopingDelay then
    PlayBanter()
    loopCounter = 0
  end
end
function PlayBanter()
  game.Audio.PlayBanter(banterName)
end
