local LD = require("design.LevelDesignLibrary")
local timers, thisObj, thisLevel, throwableSpawnID, myTimer, skipApproach, frontInteractZone, player, enabled, synchJointFacing, synchJointLocation
local respawnDelay = 1
local spawnedOnLoad = false
local spawnActive = false
local heroPuppeteer, spawnBreak, breakablePlacedComponent, crystalBreakPos, stumpParent, crystalBed, stump, crystalAnim, regenFX, throwDestroyInProgress, childAffectedObjects, childOnHitCallbacks, OnInteractFinished
local timers_LoadLibrary = function()
  if timers == nil then
    timers = require("level.timer")
  end
end
function OnScriptLoaded(level, obj)
  thisLevel = level
  thisObj = obj
  player = game.Player.FindPlayer()
  skipApproach = obj:FindLuaTableAttribute("skipApproach")
  frontInteractZone = LD.CreateInteractZone_Standard_180(obj, "promptJointFront")
  frontInteractZone:SetTags("ThrowableCrystal")
  if skipApproach then
    frontInteractZone:SetXZRange(2)
  end
  if obj:FindLuaTableAttribute("ChildAffectedObjects") ~= nil and obj:FindLuaTableAttribute("ChildAffectedObjects") ~= "" then
    childAffectedObjects = level:FindGameObjects(tostring(obj:FindLuaTableAttribute("ChildAffectedObjects") .. "*"))
  end
  childOnHitCallbacks = LD.ExtractCallbacksForEvent(level, obj, obj:FindLuaTableAttribute("ChildProjectileOnHit"))
  OnInteractFinished = LD.ExtractCallbacksForEvent(level, obj, obj:FindLuaTableAttribute("OnInteractFinished"))
  local startEnabled = thisObj:GetLuaTableAttribute("startEnabled")
  local useLOSTest = thisObj:GetLuaTableAttribute("UseLineOfSightTest")
  if startEnabled then
    enabled = true
  else
    enabled = false
  end
  if useLOSTest and frontInteractZone then
    frontInteractZone:SetEnableLineOfSightTest(true)
  end
  regenFX = obj:FindSingleGOByName("ThrowableRegenFX")
  crystalAnim = obj:FindSingleGOByName("crystalAnim")
  spawnBreak = obj:FindSingleGOByName("vibrate_spawner_crystalBreak")
  crystalBreakPos = spawnBreak:GetWorldPosition()
  print("crystal break pos ...........", crystalBreakPos)
  stumpParent = obj:FindSingleGOByName("vibrate_spawner_stump")
  crystalBed = obj:FindSingleGOByName("crystalBed_R")
  if crystalBed ~= nil then
    crystalBed:PauseAnim()
  end
  if stumpParent ~= nil then
    stump = stumpParent.Child
  end
  crystalAnim:PauseAnim()
  crystalAnim:JumpAnimToFrame(0)
  SoundInit()
  StageChange(0)
  game.SubObject.Sleep(obj)
end
function CheckForUnloadedThrowables()
  for weaponInfo in player:IterateActiveWeapons() do
    local currentWeapon = weaponInfo.Weapon
    if currentWeapon ~= nil then
      if currentWeapon:GetName() == "throwablevibrate" or currentWeapon:HasMarker("CombatThrowable") then
        return
      elseif game.Interact.IsTagSetFiltered("ThrowableCrystal") and not player:IsPlayingMove("MOV_Throwable_Pickup") and not player:IsPlayingMove("MOV_Throwable_Drop") then
        game.Interact.EnableTags("ThrowableCrystal")
      end
    end
  end
end
function OnSaveCheckpoint(level, obj)
  return {enabled = enabled}
end
function OnRestoreCheckpoint(level, obj, savedInfo)
  enabled = savedInfo.enabled
end
function OnStart(level, obj)
  if enabled then
    InteractEnable()
  else
    InteractDisable()
  end
end
function OnUseWorld(level, obj)
  if frontInteractZone:PlayerCanInteract() then
    player:RequestInteract(obj, frontInteractZone)
  end
end
function OnInteractStart(level, obj, creature)
  player:MarkCurrentWeaponMode()
  if not skipApproach then
    if stump ~= nil then
      stump:HideCollision()
    end
    LD.PlaySingleSynchMove_KratosObject(thisObj, "synchJoint", "Vibrate Crystal Spawner Interaction", "BRA_ThrowableSpawnerEnter", "", frontInteractZone, true)
  else
    StartSpawnInteract()
  end
  level:CallScript("CheckCrystalGrab")
  print("got interact start msg")
end
function OnInteractAbort(level, obj, creature)
  print("got interact Abort msg")
  game.Interact.EnableTags("ThrowableCrystal")
  CheckRespawn()
  if stump ~= nil then
    stump:ShowCollision()
  end
end
function OnInteractFinish(level, obj, creature)
  print("got interact finish msg")
  LD.ExecuteCallbacksForEvent(thisObj.Level, thisObj, OnInteractFinished, "Crystal Successfully Picked Up")
end
function OnInteractDone(level, obj, creature)
  print("got interact done msg")
  if stump ~= nil then
    stump:ShowCollision()
  end
end
function StartSpawnInteract()
  heroPuppeteer = game.Puppeteer.NewForce(thisObj, "CrystalSpawnerEnter", player)
  if heroPuppeteer ~= nil then
    heroPuppeteer:WeaponEquip({weaponMode = "Bare"})
    timers_LoadLibrary()
    timers.StartLevelTimer(0.1, StartNoApproachSync)
  end
end
function StartNoApproachSync()
  local synchJointIndex = thisObj:GetJointIndex("synchJoint")
  local synchJointFacing = thisObj:GetWorldJointForward(synchJointIndex)
  if heroPuppeteer ~= nil then
    local syncPos = thisObj:GetWorldJointPosition(synchJointIndex)
    local syncDir = thisObj:GetWorldJointForward(synchJointIndex)
    heroPuppeteer:OnComplete(ArrivedAtSpawner)
  end
end
function ArrivedAtSpawner()
  heroPuppeteer:Sync("BRA_ThrowableSpawnerEnter", true, {}, "synchJoint")
  heroPuppeteer:OnComplete(ClearHeroPup)
end
function ClearHeroPup(thisPuppeteer)
  heroPuppeteer:Clear()
  heroPuppeteer:DetachPuppet()
  heroPuppeteer = nil
end
function StageChange(myData)
  if myData == 0 then
    crystalAnim:Hide()
    regenFX:Show()
    regenFX:JumpAnimToFrame(0)
    regenFX:PlayAnimCycle()
    LD.CallFunctionAfterDelay(PlayIdleLoop, 1.25)
    PlaySpawnSound()
  elseif myData == 1 then
    print("no")
    regenFX:Hide()
    crystalAnim:Hide()
  elseif myData == 2 then
    regenFX:Show()
    regenFX:JumpAnimToFrame(0)
    regenFX:PlayAnimCycle()
    crystalAnim:Show()
    crystalAnim:JumpAnimToFrame(0)
    crystalAnim:PlayAnimToFrame(100)
    crystalAnim:SetAnimRate(3)
    timers_LoadLibrary()
    timers.StartLevelTimer(1.25, SpawnNewCrystal)
    PlaySpawnSound()
  elseif myData == 3 then
    regenFX:Show()
    regenFX:JumpAnimToFrame(0)
    regenFX:PlayAnimCycle()
    spawnBreak:Show()
  end
end
function SpawnNewCrystal()
  spawnBreak:Show()
  InteractEnable()
  PlayIdleLoop()
end
function BreakMainCrystal()
  crystalBed:JumpAnimToFrame(0)
  crystalBed:PlayAnimToFrame(60)
  spawnBreak:Hide()
end
function CheckRespawn()
  StageChange(2)
end
function InteractEnable()
  enabled = true
  frontInteractZone:Enable()
end
function InteractDisable()
  enabled = false
  frontInteractZone:Disable()
end
function LuaHook_StartSpawnFX()
  local grabFX = game.FX.Spawn("vibrate_spawnerGrab", thisLevel, {
    GameObject = thisObj,
    Joint = "spawnJoint1",
    AutoDelete = true
  })
  BreakMainCrystal()
end
function LuaHook_SpawnAndAttachThrowable(level, obj)
  local spawnTemplate = {
    SpawnObject = "gothrowableVibrateCrystal_dragon",
    HookName = "LuaHook_OnThrowableCreated",
    Level = level,
    OffsetPosition = game.Player.FindPlayer().WorldPosition - engine.Vector.New(0, 0, -10)
  }
  thisObj:SpawnGameObject(spawnTemplate)
end
function LuaHook_OnThrowableCreated(level, spawnerObject, spawnedObject)
  local newSpawn = spawnedObject
  throwableSpawnID = newSpawn.Child
  if childOnHitCallbacks ~= nil and childOnHitCallbacks ~= "" then
    throwableSpawnID.LuaObjectScript.SetParentOnHitCallback(childOnHitCallbacks)
  end
  if childAffectedObjects ~= nil and childAffectedObjects ~= "" then
    throwableSpawnID.LuaObjectScript.SetParentAffectedObjects(childAffectedObjects)
  end
  print("newspawn is...", newSpawn)
  print("throwable is...", throwableSpawnID)
  SetThrowableOnChild()
  timers_LoadLibrary()
  timers.StartLevelTimer(respawnDelay, CheckRespawn)
  StopIdleLoop()
end
function SetThrowableOnChild()
  if throwableSpawnID ~= nil then
    StageChange(1)
    throwableSpawnID.LuaObjectScript.SetThrowable(throwableSpawnID)
  end
end
function OnRecycleSpawnedObject(Level, GameObject, RefObject)
  local destroyedCrystalChild = RefObject.Child
  local childCrystalPos = destroyedCrystalChild:GetWorldPosition()
  game.Interact.EnableTags("ThrowableCrystal")
  local fx = game.FX.Spawn("vibratecrystal_decay", thisLevel, {AutoDelete = true})
  fx:SetWorldPosition(childCrystalPos)
  print("Spawned object about to be recycled!", destroyedCrystalChild, childCrystalPos)
end
function OnSpawnedObjectDestroyed(level, spawnerObject)
  game.Interact.EnableTags("ThrowableCrystal")
  print("PARENT NOTIFICATION...I GOT DESTROYEED")
end
emitter = nil
spawning = false
function SoundInit()
  emitter = thisObj:FindSingleSoundEmitterByName("SNDThrowableCrystalSpawner")
end
function PlaySpawnSound()
  if spawning == false then
    spawning = true
    LD.PlaySound(emitter, "SND_WPN_Bifrost_Bomb_Regrow")
    timers_LoadLibrary()
    timers.StartLevelTimer(respawnDelay + 0.2, function()
      spawning = false
    end)
  end
end
function PlayIdleLoop()
  LD.PlayRestartableSoundLoop(emitter, "SND_WPN_Bifrost_Bomb_Idle_LP")
end
function StopIdleLoop()
  LD.StopRestartableSoundLoop(emitter, "SND_WPN_Bifrost_Bomb_Idle_LP")
end
