local LD = require("design.LevelDesignLibrary")
local timers = require("level.timer")
local thisObj, thisLevel, Roots, Horns, Hairs, DecayCompleteCallbacks
local Decayed = false
local hornsAnimated = 0
local PreDecayFrameLength_Real = 90
local PreDecayFrameLength_Input, PreDecayAnimRate
local DecayFrameLength_Real = 30
local DecayFrameLength_Input, DecayAnimRate, HideCollisionPoint
local IsPreDecayComplete = false
local IsHornDecayComplete = false
local sequenceName, sequence, idlePercent
local useLight = false
local thisTimer, breakDelayTime, HideHorns, HideHairs, BreakHorns, PreDecay, PreDecay_Complete, HornDecay_Phase1, HornsAnimatedCallback, HornDecay_Phase2, HornDecay_Complete, Decay_Phase1, Decay_Phase2, Decay_Phase3, Decay_Phase4, LoopIdleAnim, LoopHairIdle, PlayHitReact, ResetHitReact
function Callback_LoopIdleAnim()
  LoopIdleAnim()
end
function Callback_LoopHairIdle(level, obj, hair)
  LoopHairIdle(level, obj, hair)
end
function Callback_PreDecay_Complete()
  PreDecay_Complete()
end
function Callback_HornsAnimatedCallback()
  HornsAnimatedCallback()
end
function Callback_Decay_Phase2()
  Decay_Phase2()
end
function Callback_Decay_Phase3()
  Decay_Phase3()
end
function Callback_ResetHitReact()
  ResetHitReact()
end
local DefineDecayFunctions = function()
  function HideHorns()
    if Horns then
      for _, horn in pairs(Horns) do
        horn:Hide()
      end
    end
  end
  function HideHairs()
    if Hairs then
      Hairs:Hide()
    end
  end
  function BreakHorns()
    for _, horn in pairs(Horns) do
      if horn:IsBreakable() and not horn:GetBreakable().Broken then
        horn:GetBreakable():Break()
      else
        horn:Hide()
      end
    end
    HideHairs()
  end
  function PreDecay()
    Roots:PlayAnimationToEnd({Animation = "PreDecay", Rate = PreDecayAnimRate})
    Roots:OnAnimationDone(thisObj, "Callback_PreDecay_Complete", {Animation = "PreDecay", Force = true})
  end
  function PreDecay_Complete()
    IsPreDecayComplete = true
    if sequence == 0 or sequence == 1 then
      if IsHornDecayComplete then
        Decay_Phase1()
      end
    elseif sequence == 2 then
      if Horns then
        HornDecay_Phase1()
        Roots:ClearAllAnimationCallbacks()
        Roots:PlayAnimationToEnd()
      else
        Decay_Phase1()
      end
    end
  end
  function HornDecay_Phase1()
    if Hairs then
      Hairs:ClearAllAnimationCallbacks()
      Hairs:JumpAnimationToFrame(300)
      Hairs:PlayAnimationToEnd()
    end
    if not Horns or #Horns <= 0 then
      HornDecay_Phase2()
    end
    if Horns then
      local newTimer = StartLevelTimer(breakDelayTime, HornDecay_Phase2)
    end
  end
  function HornsAnimatedCallback()
    hornsAnimated = hornsAnimated + 1
    if hornsAnimated >= #Horns then
      HornDecay_Phase2()
    end
  end
  function HornDecay_Phase2()
    if Horns then
      BreakHorns()
    end
    HornDecay_Complete()
  end
  function HornDecay_Complete()
    IsHornDecayComplete = true
    if sequence == 0 or sequence == 2 then
      if IsPreDecayComplete then
        Decay_Phase1()
      end
    elseif sequence == 1 then
      PreDecay()
    end
  end
  function Decay_Phase1()
    Roots:PlayAnimationToPercent(HideCollisionPoint, {Animation = "Decay", Rate = DecayAnimRate})
    Roots:PlayAnimationToEnd(HideCollisionPoint, {
      Animation = "ParticleDecay",
      Rate = DecayAnimRate * 3
    })
    Roots:OnAnimationDone(thisObj, "Callback_Decay_Phase2", {Animation = "Decay", Force = true})
  end
  function Decay_Phase2()
    thisObj:HideCollision()
    for _, child in pairs(thisObj.Descendants) do
      if child:IsDescendantDynamicallyParentedTo(thisObj) == false and child:IsBreakable() == false then
        child:HideCollision()
      end
    end
    if DecayCompleteCallbacks then
      LD.ExecuteCallbacksForEvent(thisLevel, thisObj, DecayCompleteCallbacks, "Decay Complete")
    end
    Roots:PlayAnimationToEnd({Rate = DecayAnimRate})
    Roots:OnAnimationDone(thisObj, "Callback_Decay_Phase3", {Force = true})
  end
  function Decay_Phase3()
    thisTimer:Start()
    if Hairs then
      Hairs:ClearAllAnimationCallbacks()
    end
    if Horns then
      for _, horn in pairs(Horns) do
        horn:ClearAllAnimationCallbacks()
      end
    end
    Roots:ClearAllAnimationCallbacks()
  end
  function Decay_Phase4()
    thisObj:Hide()
  end
  function LoopIdleAnim()
    Roots:StartAnim("Idle")
    Roots:OnAnimDone(thisObj, "Callback_LoopIdleAnim")
    Roots:JumpAnimToFrame(0)
    Roots:PlayAnimToEnd()
  end
  function LoopHairIdle()
    if Hairs then
      Hairs:JumpAnimationToFrame(0)
      Hairs:PlayAnimationToFrame(300)
      Hairs:OnAnimationDone(thisObj, "Callback_LoopHairIdle", {Force = true})
    end
  end
  function PlayHitReact()
    if not Decayed then
      idlePercent = Roots.AnimPercent or 0
      Roots:ClearAllAnimationCallbacks()
      Roots:PlayAnimationToEnd({Animation = "HitReact"})
      Roots:OnAnimationDone(thisObj, "Callback_ResetHitReact", {Animation = "HitReact"})
    end
  end
  function ResetHitReact()
    Roots:JumpAnimationToFrame(0, {Animation = "HitReact"})
    Roots:ClearAllAnimationCallbacks()
    Roots:JumpAnimationToPercent(idlePercent, {Animation = "Idle"})
    Roots:PlayAnimationCycle({Animation = "Idle"})
  end
end
function OnScriptLoaded(level, obj)
  thisObj = obj
  thisLevel = level
  thisTimer = StartLevelTimer(0.25, Decay_Phase4)
  thisTimer:Stop()
  DefineDecayFunctions()
  PreDecayFrameLength_Input = thisObj:FindLuaTableAttribute("PreDecayFrameLength") or 90
  DecayFrameLength_Input = thisObj:FindLuaTableAttribute("DecayFrameLength") or 30
  breakDelayTime = thisObj:FindLuaTableAttribute("BreakDelayLength") or 0.05
  PreDecayAnimRate = PreDecayFrameLength_Real / PreDecayFrameLength_Input
  DecayAnimRate = DecayFrameLength_Real / DecayFrameLength_Input
  HideCollisionPoint = thisObj:FindLuaTableAttribute("HideCollisionPoint") or 0.5
  sequenceName = thisObj:FindLuaTableAttribute("CrustSequence") or "HornDecay and PreDecay Parallel"
  useLight = thisObj:FindLuaTableAttribute("UseLight")
  if thisObj:FindLuaTableAttribute("StartEnabled") then
    thisObj:Show()
  else
    thisObj:Hide()
  end
  if thisObj:FindLuaTableAttribute("DecayCompleteCallbacks") then
    DecayCompleteCallbacks = LD.ExtractCallbacksForEvent(thisLevel, thisObj, thisObj:FindLuaTableAttribute("DecayCompleteCallbacks"))
  end
  Roots = thisObj:FindSingleGOByName("Root_RN").Child
  if Roots:FindSingleGOByName("HORNS") then
    Horns = Roots:FindSingleGOByName("HORNS").Children
  end
  if Roots:FindSingleGOByName("HAIRS") then
    Hairs = Roots:FindSingleGOByName("HAIRS")
  end
  if Horns then
    for i = 1, #Horns do
      Horns[i] = Horns[i].Child
    end
  end
  SoundInit()
end
function OnStart(level, obj)
  if Decayed then
    HideHorns()
    HideHairs()
    thisObj:HideCollision()
    thisObj:HideLights()
    thisObj:Hide()
  else
    Roots:JumpAnimationToFrame(0, {
      Animation = "ParticleDecay"
    })
    Roots:PauseAnimation({
      Animation = "ParticleDecay"
    })
    Roots:JumpAnimationToFrame(0, {Animation = "PreDecay"})
    Roots:PauseAnimation({Animation = "PreDecay"})
    Roots:JumpAnimationToFrame(0, {Animation = "Decay"})
    Roots:PauseAnimation({Animation = "Decay"})
    Roots:JumpAnimationToFrame(0, {Animation = "HitReact"})
    Roots:PauseAnimation({Animation = "HitReact"})
    Roots:PlayAnimationCycle({Animation = "Idle"})
    if Hairs then
      Hairs:JumpAnimationToFrame(0)
      Hairs:PlayAnimationToFrame(300)
      Hairs:OnAnimationDone(thisObj, "Callback_LoopHairIdle", {Force = true})
    end
    if sequenceName == "HornDecay and PreDecay Parallel" then
      sequence = 0
    elseif sequenceName == "HornDecay then PreDecay" then
      sequence = 1
    else
      sequence = 2
    end
    if useLight then
      Roots:ShowLights()
    else
      Roots:HideLights()
    end
  end
end
function OnSaveCheckpoint(level, obj)
  return {Decayed = Decayed}
end
function OnRestoreCheckpoint(level, obj, savedInfo)
  Decayed = savedInfo.Decayed
end
function StartDecay()
  Decayed = true
  if sequence == 0 then
    PreDecay()
    HornDecay_Phase1()
  elseif sequence == 1 then
    HornDecay_Phase1()
  elseif sequence == 2 then
    if Horns then
      PreDecay()
    else
      Decay_Phase1()
    end
  end
  PlaySoundOnDecay()
end
function OnHitByWeapon()
  PlayHitReact()
end
function OnHitByArrow()
  PlayHitReact()
end
local blockerSoundEmitter
local decaySoundEvent = "SND_BRK_Hive_Tendril_Chest_Unravel"
function SoundInit()
  blockerSoundEmitter = thisObj:FindSingleSoundEmitterByName("SNDChestHiveBlocker")
end
function PlaySoundOnDecay()
  LD.PlaySoundRingOut(blockerSoundEmitter, decaySoundEvent)
end
