local LD = require("design.LevelDesignLibrary")
local enabled
local hasOpened = false
local lootInProgress, stage0mesh, stage1mesh, stage3mesh, isCombatRift, combatIntiatesFromInteract, skipLootAfterCombat, onOpenedEvent, combatStartedEvent, combatEndedEvent, onInteractStartCallbacks, RewardTier, RewardTierIndex, WADName, lootObject, frontInteractZone, thisLevel, thisObj, player, regionSummaryQuest, soundEmitter, pocketRiftSoundGroup
function OnScriptLoaded(level, obj)
  thisLevel = level
  thisObj = obj
  player = game.Player.FindPlayer()
  stage0mesh = obj.Parent:FindSingleGOByName("stage0_Idle")
  stage1mesh = obj.Parent:FindSingleGOByName("stage1_Glitch")
  stage3mesh = obj.Parent:FindSingleGOByName("SpawnAnim")
  pocketRiftSoundGroup = thisObj:FindSingleGOByName("pocketRiftSound")
  regionSummaryQuest = obj:FindLuaTableAttribute("regionSummaryQuest")
  isCombatRift = thisObj:FindLuaTableAttribute("isCombatRift")
  skipLootAfterCombat = thisObj:FindLuaTableAttribute("skipLootAfterCombat")
  combatIntiatesFromInteract = thisObj:FindLuaTableAttribute("combatIntiatesFromInteract")
  enabled = thisObj:FindLuaTableAttribute("StartEnabled")
  if obj:FindLuaTableAttribute("onOpenedEvent") ~= nil then
    onOpenedEvent = LD.ExtractCallbacksForEvent(thisLevel, thisObj, obj:FindLuaTableAttribute("onOpenedEvent"))
  end
  if obj:FindLuaTableAttribute("combatStartedEvent") ~= nil then
    combatStartedEvent = LD.ExtractCallbacksForEvent(thisLevel, thisObj, obj:FindLuaTableAttribute("combatStartedEvent"))
  end
  if obj:FindLuaTableAttribute("combatEndedEvent") ~= nil then
    combatEndedEvent = LD.ExtractCallbacksForEvent(thisLevel, thisObj, obj:FindLuaTableAttribute("combatEndedEvent"))
  end
  RewardTier = obj:FindLuaTableAttribute("RewardTier") or 0
  RewardTierIndex = obj:FindLuaTableAttribute("RewardTierIndex") or 0
  WADName = obj:FindLuaTableAttribute("WADName")
  if WADName == nil or WADName == "" then
    WADName = "TB"
  end
  lootObject = obj.Parent:FindSingleGOByName("LootObject")
  frontInteractZone = LD.CreateInteractZone_Standard_360(obj, "promptJointFront")
  frontInteractZone:SetDebugOffset(0, 0, 2)
  frontInteractZone:SetTags("CarryActive")
  if not combatIntiatesFromInteract then
    frontInteractZone:Disable()
  end
  SoundInit()
  game.SubObject.Sleep(obj)
end
function OnFirstStart(level, obj)
  if enabled then
    if not isCombatRift then
      SetVisualState(0)
      Enable()
    else
      SetVisualState(1)
    end
  else
    Disable()
  end
  if lootObject then
    for _, desc in pairs(lootObject.Descendants) do
      desc:Hide()
    end
  end
  HideStage3()
  thisObj:HideCollision()
end
function OnStart(level, obj)
  if not hasOpened then
    if enabled then
      if not isCombatRift then
        SetVisualState(0)
        Enable()
      else
        SetVisualState(1)
      end
    else
      Disable()
    end
  else
    Disable()
  end
  thisObj:HideCollision()
end
function OnUseWorld(level, obj)
  if frontInteractZone:PlayerCanInteract() then
    LD.SetFacingTowardObject(obj, player)
    player:RequestInteract(obj, {
      InteractZone = frontInteractZone,
      LerpObject = lootObject.Child
    })
  end
end
function ForceInteract()
  LD.SetFacingTowardObject(thisObj, player)
  player:RequestInteract(thisObj, {
    InteractZone = frontInteractZone,
    LerpObject = lootObject.Child
  })
end
function OnInteractStart(level, obj, creature)
  LD.PlaySingleSynchMove_KratosObject(thisObj, "syncJoint", "Pocket Rift Interaction", "BRA_bifrostPockRiftEnter", "", frontInteractZone, true)
  FireOnInteractStartCallbacks()
  CameraApproach()
end
function LuaHook_CheckForCombatState()
  if combatIntiatesFromInteract then
    StartCombatState()
    local concussionParams = {
      Tweak = "CNC_PocketRiftKnockBack",
      WorldLocation = player:GetWorldPosition(),
      GameObject = thisObj,
      EnemyId = player:GetID()
    }
    game.Combat.PlayConcussion(concussionParams)
  end
end
function InteractEnable()
  enabled = true
  if frontInteractZone ~= nil then
    frontInteractZone:Enable()
  end
end
function InteractDisable()
  enabled = false
  if frontInteractZone ~= nil then
    frontInteractZone:Disable()
  end
end
function Enable()
  if not hasOpened then
    PlayTransitionFx()
    if isCombatRift then
      SetVisualState(1)
    else
      SetVisualState(0)
    end
    thisObj:HideCollision()
    InteractEnable()
    if lootObject then
      for _, desc in pairs(lootObject.Descendants) do
        desc:Hide()
      end
    end
    pocketRiftSoundGroup:Show()
    PlaySoundInIdle()
  end
end
function SpawnInAndEnable()
  PlayTransitionFx()
  InteractEnable()
  SetVisualState(0)
  PlaySoundInIdle()
end
function Disable()
  StopSoundInIdle()
  HideStage0()
  HideStage1()
  HideStage3()
  InteractDisable()
end
function IsOpen()
  return hasOpened
end
function Lock()
  if frontInteractZone ~= nil then
    frontInteractZone:Lock()
  end
end
function Unlock()
  if frontInteractZone ~= nil then
    frontInteractZone:Unlock()
  end
end
function RegisterOnInteractStartCallback(fn)
  if onInteractStartCallbacks == nil then
    onInteractStartCallbacks = {}
  end
  onInteractStartCallbacks[#onInteractStartCallbacks + 1] = fn
end
function FireOnInteractStartCallbacks()
  if onInteractStartCallbacks ~= nil then
    for _, fn in pairs(onInteractStartCallbacks) do
      fn()
    end
  end
end
function ResetCombatState()
  if not hasOpened then
    pocketRiftSoundGroup:Show()
  end
  if lootObject then
    for _, desc in pairs(lootObject.Descendants) do
      desc:Hide()
    end
  end
  thisObj:HideCollision()
  SetVisualState(1)
  InteractEnable()
end
function HideStage3()
  stage3mesh = thisObj.Parent:FindSingleGOByName("SpawnAnim")
  if stage3mesh ~= nil then
    stage3mesh:JumpAnimToFrame(0)
    stage3mesh:PauseAnim()
    stage3mesh:Hide()
    for _, desc in pairs(stage3mesh.Descendants) do
      desc:Hide()
    end
  end
end
function HideStage1()
  print("found stage 1 mesh its.......", stage1mesh)
  if stage1mesh ~= nil then
    stage1mesh:JumpAnimToFrame(0)
    stage1mesh:PauseAnim()
    stage1mesh:Hide()
    stage1mesh:HideBehaviors()
    for _, desc in pairs(stage1mesh.Descendants) do
      desc:Hide()
      desc:HideBehaviors()
    end
  end
end
function HideStage0()
  stage0mesh = thisObj.Parent:FindSingleGOByName("stage0_Idle")
  if stage0mesh ~= nil then
    stage0mesh:Hide()
    stage0mesh:HideBehaviors()
    for _, desc in pairs(stage0mesh.Descendants) do
      desc:Hide()
      desc:HideBehaviors()
    end
  end
end
function StartCombatState()
  ShowCollision()
  InteractDisable()
  if combatStartedEvent ~= nil then
    LD.ExecuteCallbacksForEvent(thisLevel, thisObj, combatStartedEvent, "combatStartedEvent")
  end
  SetVisualState(3)
  player:CallScript("LuaHook_PocketRiftCombatStarted")
end
function ShowCollision()
  thisObj:ShowCollision()
end
function SpawningDone()
  if combatIntiatesFromInteract == true then
    SetVisualState(4)
    thisObj:HideCollision()
  end
end
function StopCombatState()
  thisObj:HideCollision()
  stage3mesh:JumpAnimToFrame(75)
  stage3mesh:PlayAnimToEnd()
  enabled = true
  combatIntiatesFromInteract = false
  isCombatRift = false
  stage3mesh:OnAnimDone(thisObj, "PostCombatState")
  if combatEndedEvent ~= nil then
    LD.ExecuteCallbacksForEvent(thisLevel, thisObj, combatEndedEvent, "combatEndedEvent")
  end
  player:CallScript("LuaHook_PocketRiftCombatSuccessful")
end
function PostCombatState()
  thisObj:HideCollision()
  if not skipLootAfterCombat then
    stage3mesh:ClearAllAnimCallbacks()
    PlayTransitionFx()
    if stage3mesh ~= nil then
      stage3mesh:Destroy()
    end
    if stage1mesh ~= nil then
      stage1mesh:Destroy()
    end
    if stage0mesh ~= nil then
      stage0mesh:SetScale(2.5)
    end
    SetVisualState(0)
    Enable()
  else
    stage3mesh:ClearAllAnimCallbacks()
    PlayTransitionFx()
    SetVisualState(5)
  end
end
function LuaHook_SpawnFX01()
  local transitionFX = game.FX.Spawn("pocketrift_spawn_transition", thisLevel, {
    GameObject = thisObj,
    Joint = "lootSpawnFX",
    Scale = 1.5,
    Follow = true,
    AutoDelete = true
  })
end
function PlayTransitionFx()
  if combatIntiatesFromInteract then
    local transitionFX = game.FX.Spawn("pocketrift_spawn_transition", thisLevel, {
      GameObject = thisObj,
      Joint = "lootSpawnFX",
      Follow = true,
      AutoDelete = true
    })
  else
    local transitionFXAlt = game.FX.Spawn("pocketrift_spawn_transition", thisLevel, {
      GameObject = thisObj,
      Joint = "lootSpawnFX",
      Follow = true,
      AutoDelete = true
    })
  end
end
function SetCombatIntiatesFromInteract()
  combatIntiatesFromInteract = true
  frontInteractZone:Enable()
end
function SetIsCombatRift()
  isCombatRift = true
end
function SetVisualState(data)
  if data == 0 then
    print("Pocket Rift Entering stage 0")
    stage0mesh = thisObj.Parent:FindSingleGOByName("stage0_Idle")
    print("Stage 0 mesh is...", stage0mesh)
    if stage0mesh ~= nil then
      stage0mesh:Show()
      stage0mesh:ShowBehaviors()
      stage0mesh:SetScale(2.5)
      for _, desc in pairs(stage0mesh.Descendants) do
        desc:ShowBehaviors()
        desc:Show()
      end
      stage0mesh:JumpAnimToFrame(0)
      stage0mesh:PlayAnimCycle()
    end
    HideStage1()
    HideStage3()
    PlaySoundInIdle()
  elseif data == 1 then
    print("Pocket Rift Entering stage 1")
    stage1mesh:Show()
    HideStage0()
    HideStage3()
    PlaySoundInIdle()
  elseif data == 2 then
    local interactFX = game.FX.Spawn("pocketrift_interact_loot", thisLevel, {
      GameObject = thisObj,
      Joint = "lootSpawnFX",
      AutoDelete = true
    })
    PlayTransitionFx()
    print("Pocket Rift Entering stage 2")
    HideStage0()
    HideStage1()
    HideStage3()
    StopSoundInIdle()
    PlaySoundOnInteract()
  elseif data == 3 then
    print("Pocket Rift Entering stage 3")
    stage3mesh:Show()
    PlayTransitionFx()
    stage3mesh:PlayAnimToFrame(30)
    HideStage0()
    HideStage1()
    StopSoundInIdle()
    PlaySoundOnInteract_CombatPortal()
  elseif data == 4 then
    print("Pocket Rift Entering Agitated state")
    if stage3mesh ~= nil then
      stage3mesh:Show()
      stage3mesh:JumpAnimToFrame(60)
      stage3mesh:PlayAnimToFrame(75)
    end
    HideStage0()
    HideStage1()
    PlaySoundCombatPortalClose()
  else
    print("Pocket Rift Entering unknown state")
    HideStage0()
    HideStage1()
    stage3mesh:Destroy()
  end
end
function LuaHook_PlayerEnteredRift()
  if not combatIntiatesFromInteract then
    SetVisualState(2)
    PlaySoundLootIdle()
    lootInProgress = true
  end
end
function LuaHook_SpawnLoot()
  lootObject:Show()
end
function LuaHook_GivePockeRiftLoot()
  if lootObject then
    lootObject:Hide()
  end
  if thisObj:FindLuaTableAttribute("onOpenedEvent") ~= nil then
    LD.ExecuteCallbacksForEvent(thisLevel, thisObj, onOpenedEvent, "onOpenedEvent")
  end
  local rewardName = "MISC_LEGENDARY_TIER"
  LD.RollContainerConditionLoot(rewardName, RewardTier, WADName, RewardTierIndex, thisObj:GetName())
  CheckQuestState()
end
function CheckQuestState()
  local questState = game.QuestManager.GetQuestState("Quest_Labor_RiftPockets_Parent")
  if questState == "Inactive" then
    game.QuestManager.StartQuest("Quest_Labor_RiftPockets_Parent")
  end
  local questStateBronze = game.QuestManager.GetQuestState("Quest_Labor_RiftPockets_Bronze")
  local questStateSilver = game.QuestManager.GetQuestState("Quest_Labor_RiftPockets_Silver")
  game.QuestManager.IncrementQuestProgress("Quest_Labor_RiftPockets", 1)
  if questStateBronze == "Active" then
    game.QuestManager.IncrementQuestProgress("Quest_Labor_RiftPockets_Bronze", 1)
  end
  if questStateSilver == "Active" then
    game.QuestManager.IncrementQuestProgress("Quest_Labor_RiftPockets_Silver", 1)
  end
  if regionSummaryQuest ~= nil and regionSummaryQuest ~= "" then
    regionSummaryQuest = string.gsub(regionSummaryQuest, "%s+", "")
    LD.ActivateAndIncrementQuest(regionSummaryQuest)
  end
end
function OnInteractFinish(level, obj, creature)
  if lootInProgress then
    hasOpened = true
    game.SubObject.SoftSave(thisObj)
    print("soft saving")
  end
end
function OnSaveCheckpoint(level, obj)
  return {
    enabled = enabled,
    hasOpened = hasOpened,
    combatIntiatesFromInteract = combatIntiatesFromInteract,
    isCombatRift = isCombatRift
  }
end
function OnRestoreCheckpoint(level, obj, tab)
  enabled = tab.enabled
  hasOpened = tab.hasOpened
  combatIntiatesFromInteract = tab.combatIntiatesFromInteract
  isCombatRift = tab.isCombatRift
end
function CameraApproach()
  game.Camera.Recenter({
    TimeStart = 0,
    TimeDuration = 2,
    LockRecenter = 1,
    YawRange = -1,
    TriggerLeft = 0,
    TriggerRight = 0,
    ReturnLeft = 0,
    ReturnRight = 0,
    PitchRange = 0,
    ReturnUp = -8,
    ReturnDown = -8
  })
end
local soundEvents = {
  IdleLoop = "SND_LOOT_Rift_Pocket_LP",
  OnInteract = "SND_LOOT_Rift_Pocket_Reach_In",
  CombatPortalOpen = "SND_LOOT_Rift_Pocket_Portal_Gate_Open",
  CombatPortalClose = "SND_LOOT_Rift_Pocket_Portal_Gate_Close",
  CombatPortalEnemySpawn = "SND_LOOT_Rift_Pocket_Portal_Gate_Enemy_Exit",
  CombatPortalLoop = "SND_LOOT_Rift_Pocket_Portal_LP",
  LootIdleLoop = "SND_LOOT_Shard_Purple_Idle_LP"
}
function SoundInit()
  soundEmitter = pocketRiftSoundGroup:FindSingleSoundEmitterByName("SNDPocketRift")
end
function SoundSetup(sounds)
  if sounds ~= nil then
    if sounds.SoundEmitter ~= nil then
      soundEmitter = thisObj:FindSingleSoundEmitterByName(sounds.SoundEmitter)
    end
    for key in pairs(soundEvents) do
      for newKey, newValue in pairs(sounds) do
        if newKey == key and newValue ~= nil and newValue ~= "" then
          soundEvents[key] = newValue
        end
      end
      LD.SoundDebug(tostring(key) .. ": " .. tostring(soundEvents[key]))
    end
  end
end
function PlaySoundInIdle()
  LD.PlayRestartableSoundLoop(soundEmitter, soundEvents.IdleLoop)
end
function StopSoundInIdle()
  LD.StopRestartableSoundLoop(soundEmitter, soundEvents.IdleLoop)
end
function PlaySoundOnInteract()
  LD.PlaySound(soundEmitter, soundEvents.OnInteract)
end
function PlaySoundOnInteract_CombatPortal()
  LD.PlaySound(soundEmitter, soundEvents.CombatPortalOpen)
  PlaySoundCombatPortalLoop()
end
function PlaySoundCombatPortalClose()
  StopSoundCombatPortalLoop()
  LD.PlaySound(soundEmitter, soundEvents.CombatPortalClose)
  LD.PlaySoundOnFrame(soundEmitter, stage3mesh, soundEvents.IdleLoop, 75)
end
function PlaySoundCombatPortalLoop()
  LD.PlayRestartableSoundLoop(soundEmitter, soundEvents.CombatPortalLoop)
end
function StopSoundCombatPortalLoop()
  LD.StopRestartableSoundLoop(soundEmitter, soundEvents.CombatPortalLoop)
end
function PlaySoundCombatPortalEnemySpawn()
  LD.PlaySound(soundEmitter, soundEvents.CombatPortalEnemySpawn)
end
function PlaySoundLootIdle()
  local lootSoundEmitter = thisObj.Parent:FindSingleGOByName("LootPocketGeo"):FindSingleGOByName("LootObject").Child.SoundEmitters[1]
  if lootSoundEmitter then
    LD.PlaySound(lootSoundEmitter, soundEvents.LootIdleLoop)
  end
end
