local LD = require("design.LevelDesignLibrary")
local timer = require("level.timer")
local thisObj, thisLevel, enabled, temporalObject, onCrystalFullyLitEvents, onCrystalFullyUnlitEvents, socketed, fullyLitCallbacks, fullyUnlitCallbacks, subFX, nestedFX, fullyLitMesh
local crystalActive = false
findObjectTemporalOnly = nil
bridgeCount = 0
bridgesOff = 0
function OnScriptLoaded(level, obj)
  thisObj = obj
  thisLevel = level
  obj:AddMarker("SonTarget")
  local parentObj = obj.Parent
  findObjectTemporalOnly = obj:GetLuaTableAttribute("FindObjecTemporalOnly")
  if obj:FindLuaTableAttribute("CrystalFullyLit") ~= nil then
    onCrystalFullyLitEvents = LD.ExtractCallbacksForEvent(level, obj, obj:FindLuaTableAttribute("CrystalFullyLit"))
  end
  if obj:FindLuaTableAttribute("CrystalFullyUnlit") ~= nil then
    onCrystalFullyUnlitEvents = LD.ExtractCallbacksForEvent(level, obj, obj:FindLuaTableAttribute("CrystalFullyUnlit"))
  end
  if obj:GetLuaTableAttribute("TemporalObject") ~= nil and obj:GetLuaTableAttribute("TemporalObject") ~= "" then
    if findObjectTemporalOnly then
      temporalObject = obj:FindSingleGOByName("temporalBrazier")
    else
      temporalObject = level:GetGameObject(tostring(obj:GetLuaTableAttribute("TemporalObject")))
    end
  end
  enabled = obj:GetLuaTableAttribute("Enabled")
  crystalActive = obj:GetLuaTableAttribute("CrystalActive")
  fullyLitMesh = obj:FindSingleGOByName("FullyLitMesh")
  print("fully lit and new mesh is...", fullyLitMesh)
  subFX = obj:FindSingleGOByName("bifrost_crystal_temporal_active")
  subFX:Hide()
  print("SUB FX IS.....", subFX)
  nestedFX = subFX:FindSingleGOByName("vis_part1")
  SoundInit()
  print("Temporal Object is...", temporalObject)
  game.SubObject.Sleep(obj)
end
function OnFirstStart(level, obj)
  if crystalActive then
    SetCrystalObjectStates(2)
  elseif not crystalActive and socketed then
    SetCrystalObjectStates(1)
  else
    SetCrystalObjectStates(0)
  end
end
function OnHitByArrow(level, go, arrow_owner, arrow_go, arrow_tweak)
  if arrow_go:GetName() == "bifrost_projectile" and enabled then
    if not crystalActive then
      SetCrystalObjectStates(2)
      print("WAS PRISMATIC")
      if thisObj:GetLuaTableAttribute("OnCrystalLitFirstTime") ~= nil then
        LD.ExtractAndExecuteCallbacksForEvent(thisLevel, thisObj, thisObj:GetLuaTableAttribute("OnCrystalLitFirstTime"), "Crystal first light")
      end
      PlaySoundActivateCrystal()
    else
      SetCrystalObjectStates(3)
      ActivatePulse()
    end
  elseif arrow_go:GetName() == "bifrost_projectile" and not enabled then
    print("HIT BY.....enabled", arrow_go, enabled)
    ActivatePulse()
    PlayFailedEffectAlt()
    if thisObj:GetLuaTableAttribute("Event_OnHitAndNotEnabled") ~= nil and thisObj:GetLuaTableAttribute("Event_OnHitAndNotEnabled") ~= "" then
      LD.ExtractAndExecuteCallbacksForEvent(thisLevel, thisObj, thisObj:GetLuaTableAttribute("Event_OnHitAndNotEnabled"), "Crystal not Enabled")
    end
  end
end
function OnHitByWeapon(level, obj, weapon, attacker)
  if attacker == game.Player.FindPlayer() then
    game.Audio.IncrementBanterFact("HitBifrost", 1, 10)
    game.Audio.PlayBanterNonCritical("ca_carry_crystal_weapon_hit")
  end
end
function ActivatePulse()
  local objPos = thisObj:GetWorldPosition()
  local pulseFX = game.FX.Spawn("bifrost_crystal_temporal_pulse", thisLevel, {AutoDelete = true})
  pulseFX:SetWorldPosition(objPos)
  local concussionParams = {
    Tweak = "CNC_Light_Crystal_Pulse",
    WorldLocation = objPos,
    GameObject = thisObj,
    EnemyId = game.AI.FindSon():GetID()
  }
  game.Combat.PlayConcussion(concussionParams)
  PlayLightPulseSound()
end
function OnFullyLit(functionToCall)
  if fullyLitCallbacks == nil then
    fullyLitCallbacks = {}
  end
  table.insert(fullyLitCallbacks, functionToCall)
end
function FireFullyLitCallbacks()
  if fullyLitCallbacks ~= nil then
    for i = 1, #fullyLitCallbacks do
      fullyLitCallbacks[i]()
    end
  end
end
function OnFullyUnlit(functionToCall)
  if fullyUnlitCallbacks == nil then
    fullyUnlitCallbacks = {}
  end
  table.insert(fullyUnlitCallbacks, functionToCall)
end
function FireFullyUnlitCallbacks()
  if fullyUnlitCallbacks ~= nil then
    for i = 1, #fullyUnlitCallbacks do
      fullyUnlitCallbacks[i]()
    end
  end
end
function SetCrystalObjectStates(data)
  if data == 0 then
    print("Temporal Crystal State 0")
    DisableTemporalObject()
    fullyLitMesh:Hide()
    fullyLitMesh:PauseAnimation()
    crystalActive = false
    FireFullyUnlitCallbacks()
    LD.ExecuteCallbacksForEvent(thisLevel, thisObj, onCrystalFullyUnlitEvents, "CrystalFullyUnlitEvents")
    SetSoundBifrostInactive()
  elseif data == 1 then
    print("Temporal Crystal State 1")
    DisableTemporalObject()
    fullyLitMesh:Hide()
    subFX:Hide()
    fullyLitMesh:PauseAnimation()
    SetSoundBifrostInactive()
  elseif data == 2 then
    print("Temporal Crystal State 2")
    fullyLitMesh:Show()
    fullyLitMesh:PlayAnimationToEnd()
    nestedFX:JumpAnimationToFrame(0)
    nestedFX:PlayAnimationToFrame(20)
    timer.StartLevelTimer(0.2, CrystalFXPeaked)
    nestedFX:Show()
    crystalActive = true
    FireFullyLitCallbacks()
    LD.ExecuteCallbacksForEvent(thisLevel, thisObj, onCrystalFullyLitEvents, "CrystalFullyLitEvents")
    SetSoundBifrostActive()
  elseif data == 3 then
    print("Temporal Crystal State 3")
    nestedFX:JumpAnimationToFrame(0)
    nestedFX:PlayAnimationToFrame(20)
    nestedFX:Show()
  else
    DisableTemporalObject()
    fullyLitMesh:Hide()
    fullyLitMesh:PauseAnimation()
    SetSoundBifrostInactive()
  end
end
function PlayFailedEffectAlt()
  local failFX = game.FX.Spawn("bifrost_temporal_fail", thisLevel, {
    GameObject = thisObj,
    Joint = "fxJoint",
    AutoDelete = true
  })
end
function SetCrystalVisualState(data)
  if data == 0 then
    if temporalObject ~= nil then
      temporalObject:Hide()
    end
  elseif data == 1 then
    if temporalObject ~= nil then
      temporalObject:Hide()
    end
  elseif data == 2 and temporalObject ~= nil then
    temporalObject:Show()
  end
end
function SetActive(active)
  crystalActive = active
end
function Enable()
  enabled = true
end
function Disable()
  enabled = false
end
function HideObjectCollision()
  thisObj:HideCollision()
end
function ShowObjectCollision()
  thisObj:ShowCollision()
end
function CrystalFXPeaked()
  EnableTemporalObject()
  nestedFX:ClearAllAnimationCallbacks()
  nestedFX:PlayAnimationToFrame(50)
end
function DisableTemporalObject()
  if temporalObject ~= nil and temporalObject ~= "" then
    if temporalObject.LuaObjectScript and temporalObject.LuaObjectScript.IsTemporalObject then
      temporalObject.LuaObjectScript.TurnTemporalObjectOff()
    else
      for _, childObj in pairs(temporalObject.Descendants) do
        print("Disabling Temporal object child..", childObj)
        if childObj.LuaObjectScript and childObj.LuaObjectScript.IsTemporalObject then
          childObj.LuaObjectScript.TurnTemporalObjectOff(TOTurnedOff)
          bridgeCount = bridgeCount + 1
        else
          childObj:HideCollision()
          childObj:Hide()
        end
      end
    end
    if bridgeCount <= 0 then
      temporalObject:HideCollision()
      temporalObject:Hide()
    end
    print("Disabling Temporal Object..", temporalObject)
  end
end
function EnableTemporalObject()
  if temporalObject ~= nil and temporalObject ~= "" then
    print("TEMPORAL OBJECT IS...", temporalObject)
    if temporalObject.LuaObjectScript and temporalObject.LuaObjectScript.IsTemporalObject then
      temporalObject.LuaObjectScript.TurnTemporalObjectOn()
    else
      for _, childObj in pairs(temporalObject.Descendants) do
        print("Enabling Temporal object child..", childObj)
        if childObj.LuaObjectScript and childObj.LuaObjectScript.IsTemporalObject then
          childObj.LuaObjectScript.TurnTemporalObjectOn()
        else
          childObj:ShowCollision()
          childObj:Show()
        end
      end
      temporalObject:ShowCollision()
      temporalObject:Show()
    end
    print("Enabling Temporal Object..", temporalObject)
  end
end
function SetTemporalObject(newTemporalObject)
  temporalObject = newTemporalObject
end
function SetSocketed(newState)
  socketed = newState
  if socketed then
    print("JUST GOT SOCKETED --CRYSTAL")
    SetCrystalObjectStates(1)
  else
    print("JUST GOT UnSOCKETED --CRYSTAL")
    SetCrystalObjectStates(0)
  end
end
function TOTurnedOff()
  bridgesOff = bridgesOff + 1
  if bridgesOff >= bridgeCount then
    temporalObject:Hide()
    temporalObject:HideCollision()
  end
end
function OnSaveCheckpoint(level, obj)
  print("Crystal  - Saving")
  return {
    crystalActive = crystalActive,
    socketed = socketed,
    enabled = enabled
  }
end
function OnRestoreCheckpoint(level, obj, savedInfo)
  enabled = savedInfo.enabled
  crystalActive = savedInfo.crystalActive
  socketed = savedInfo.socketed
  print("Crystal - Restore Checkpoint", crystalActive, socketed)
  if crystalActive then
    SetCrystalObjectStates(2)
  elseif not crystalActive and socketed then
    SetCrystalObjectStates(1)
  else
    SetCrystalObjectStates(0)
  end
end
local soundEmitter, soundEmitterName
local SNDBifrostActiveLP = "SND_MAG_Temporal_Light_Crystal_Active_LP"
local SNDBifrostInactiveLP = "SND_MAG_Temporal_Light_Crystal_Inactive_LP"
local SNDBifrostPulse = "SND_MAG_Temporal_Light_Torches_Active_Hit_Sparks"
local SNDBifrostActivation = "SND_MAG_Temporal_Light_Crystal_Active_LP_Start"
function SoundInit()
  soundEmitterName = thisObj:FindLuaTableAttribute("soundEmitterName")
  if soundEmitterName ~= nil and soundEmitterName ~= "" then
    soundEmitter = thisObj:FindSingleSoundEmitterByName(soundEmitterName)
  else
    soundEmitter = thisObj.SoundEmitters[1]
  end
end
function SetSoundBifrostActive()
  LD.StopRestartableSoundLoop(soundEmitter, SNDBifrostInactiveLP)
  LD.PlayRestartableSoundLoop(soundEmitter, SNDBifrostActiveLP)
end
function SetSoundBifrostInactive()
  LD.StopRestartableSoundLoop(soundEmitter, SNDBifrostActiveLP)
  LD.PlayRestartableSoundLoop(soundEmitter, SNDBifrostInactiveLP)
end
function PlayLightPulseSound()
  LD.PlaySound(soundEmitter, SNDBifrostPulse)
end
function PlaySoundActivateCrystal()
  LD.PlaySound(soundEmitter, SNDBifrostActivation)
end
