local LD = require("design.LevelDesignLibrary")
local timers = require("level.timer")
local ND = require("design.NarrativeDesignLibrary")
local actor = require("narrative.actor")
local LTW_STAGES = {
  STAGE_10 = 10,
  STAGE_20 = 20,
  STAGE_30 = 30,
  STAGE_40 = 40,
  STAGE_45 = 45,
  STAGE_50 = 50,
  STAGE_60 = 60,
  STAGE_70 = 70,
  STAGE_80 = 80,
  STAGE_90 = 90,
  STAGE_DONE = 500
}
local stageData = {}
local ltw_son, ltw_freya, snp_son, son, thisLevel, freActor, seq
function OnFirstStart(level)
  GameObjects.collision_IrrDwarf:HideCollision()
  GameObjects.collision_Bridge:HideCollision()
  GameObjects.collision_CineBlocker:HideCollision()
end
function OnStart(level)
  thisLevel = level
  son = game.AI.FindSon()
  stageData[LTW_STAGES.STAGE_10] = {
    freyaPoint = GameObjects.FreyaSpawn_DownFoothills,
    stageFunc = LTW_DownFoothills_Start
  }
  stageData[LTW_STAGES.STAGE_20] = {
    freyaPoint = GameObjects.FreyaSpawn_ExitGondola,
    stageFunc = LTW_ExitGondola_Start
  }
  stageData[LTW_STAGES.STAGE_30] = {
    freyaPoint = GameObjects.FreyaSpawn_ToLightbridge,
    stageFunc = LTW_ToLightbridge_Start
  }
  stageData[LTW_STAGES.STAGE_40] = {
    freyaPoint = GameObjects.FreyaSpawn_ToBridgepush,
    stageFunc = LTW_ToBridgePush_Start
  }
  stageData[LTW_STAGES.STAGE_45] = {
    freyaPoint = GameObjects.FreyaSpawn_ToBridgepush,
    stageFunc = LTW_ToBridgePush
  }
  stageData[LTW_STAGES.STAGE_50] = {
    freyaPoint = GameObjects.FreyaSpawn_OutsideAirlock,
    stageFunc = LTW_ToBridgePush_EndIdle
  }
  stageData[LTW_STAGES.STAGE_60] = {
    freyaPoint = GameObjects.FreyaSpawn_InsideAirlock,
    stageFunc = LTW_Airlock_Start
  }
  stageData[LTW_STAGES.STAGE_70] = {
    freyaPoint = GameObjects.FreyaSpawn_EnterTravelRoom,
    stageFunc = nil
  }
  stageData[LTW_STAGES.STAGE_80] = {
    freyaPoint = GameObjects.FreyaSpawn_ExitTravelRoom,
    stageFunc = LTW_ExitRealmTravel
  }
  stageData[LTW_STAGES.STAGE_90] = {
    freyaPoint = GameObjects.FreyaSpawn_InsideAirlock_ToAlf,
    stageFunc = LTW_EnterAirlock_ToAlfheim_AndSetPriority
  }
  if game.FindLevel("FreyaLvl100_Global") ~= nil and LD.FindFreya() == nil then
    SpawnFreya()
  end
end
function OnWadLoaded(level, newLevel)
  if newLevel ~= level then
    if newLevel.Name == "WAD_FreyaLvl100_Global" and LD.FindFreya() == nil then
      SpawnFreya()
    elseif newLevel.Name == "WAD_Cal120_Airlock" then
      local doorObj = newLevel:GetGameObject("SpreadDoor_Caldera_Airlock")
      if doorObj ~= nil then
        doorObj = doorObj.Child
        if doorObj ~= nil then
          local currentStage = game.Level.GetVariable("FreyaLTWStage")
          if currentStage == LTW_STAGES.STAGE_40 then
            doorObj:CallScript("Lock")
          elseif currentStage == LTW_STAGES.STAGE_50 then
            doorObj:CallScript("Unlock")
          end
        end
      end
    end
  end
end
function SpawnFreya()
  local currentStage = stageData[game.Level.GetVariable("FreyaLTWStage")]
  if currentStage == nil then
    return
  end
  if currentStage.freyaPoint ~= nil then
    print("spawning Freya at game object: " .. currentStage.freyaPoint:GetName())
    LD.SpawnFreyaAtVector(currentStage.freyaPoint:GetWorldPosition(), currentStage.freyaPoint:GetWorldForward())
  end
  if currentStage.stageFunc ~= nil then
    timers.StartLevelTimer(0.2, function()
      currentStage.stageFunc()
    end)
  end
end
function DisableLTW()
  TurnOffSonLTW()
  TurnOffFreyaLTW()
end
function TurnOffSonLTW()
  if ltw_son then
    ltw_son.LuaObjectScript.Disable()
    ltw_son = nil
  end
  TurnOffYSNP()
end
function TurnOffFreyaLTW()
  if ltw_freya then
    ltw_freya.LuaObjectScript.Disable()
    ltw_freya = nil
  end
end
function TurnOffYSNP()
  if snp_son then
    snp_son.LuaObjectScript.Disable()
    snp_son = nil
  end
end
function LTW_DownFoothills_Start()
  game.Level.SetVariable("FreyaLTWStage", LTW_STAGES.STAGE_10)
  ltw_son = GameObjects.LTW_DownFootHills_Son
  ltw_freya = GameObjects.LTW_DownFootHills_Freya
  snp_son = GameObjects.SNP_DownFootHills_Son
  ltw_son.LuaObjectScript.Enable()
  ltw_freya.LuaObjectScript.Enable()
  snp_son.LuaObjectScript.Enable()
  GameObjects.collision_Brush:HideCollision()
  son:CallScript("LuaHook_ToggleSlowdownStops", false)
end
function LTW_DownFoothills_UpdateSonFollowParams()
  local newParams_Son = {FollowerDistance_CaughtUp = 5, FollowerDistance_Continue = 7}
  ltw_son.LuaObjectScript.UpdateLeadTheWayParams(newParams_Son)
end
function LTW_DownFoothills_UpdateParams()
  local freyaWalkSpeed = 1.779
  local newParams_Freya = {
    Speed = freyaWalkSpeed,
    LeaderDistance_Wait = 100,
    LeaderDistance_Continue = 80,
    LeaderDistance_Backtrack = 200,
    LeaderDistance_BacktrackDone = 180
  }
  ltw_freya.LuaObjectScript.UpdateLeadTheWayParams(newParams_Freya)
  local sonWalkSpeed = 2.2
  local newParams_Son = {
    Speed = sonWalkSpeed,
    FollowerDistance_CaughtUp = 1,
    FollowerDistance_Continue = 2
  }
  ltw_son.LuaObjectScript.UpdateLeadTheWayParams(newParams_Son)
end
function LTW_ExitGondola_Start()
  local stage = game.Level.GetVariable("FreyaLTWStage")
  if stage == 0 or stage > LTW_STAGES.STAGE_20 then
    return
  end
  game.Level.SetVariable("FreyaLTWStage", LTW_STAGES.STAGE_20)
  DisableLTW()
  ltw_son = GameObjects.LTW_ExitGondola_Son
  ltw_freya = GameObjects.LTW_ExitGondola_Freya
  ltw_son.LuaObjectScript.Enable()
  ltw_freya.LuaObjectScript.Enable()
  GameObjects.CA_Observe_Forward_Up_SonLowerGondola.LuaObjectScript.Enable()
  CreateFreyaIdleSequence(GameObjects.Freya_Fake_CA, "synchJoint")
end
function LTW_ToLightbridge_Start()
  local stage = game.Level.GetVariable("FreyaLTWStage")
  if stage == 0 or stage > LTW_STAGES.STAGE_30 then
    return
  end
  game.Level.SetVariable("FreyaLTWStage", LTW_STAGES.STAGE_30)
  DisableLTW()
  ltw_son = GameObjects.LTW_ToLightbridge_Son
  ltw_freya = GameObjects.LTW_ToLightbridge_Freya
  snp_son = GameObjects.SNP_ToLightBridge_Son
  ltw_son.LuaObjectScript.Enable()
  ltw_freya.LuaObjectScript.Enable()
  snp_son.LuaObjectScript.Enable()
  GameObjects.collision_Bridge:ShowCollision()
  GameObjects.collision_CineBlocker:ShowCollision()
  GameObjects.CA_Observe_Forward_Up_SonLowerGondola.LuaObjectScript.Disable()
  GameObjects.Freya_Fake_CA:HideEntityVolume()
  if seq ~= nil then
    seq:Complete()
  end
end
function LTW_ToLightbridge_HideBlockerCollision()
  GameObjects.collision_CineBlocker:HideCollision()
end
function Cal250Triptych_TurnOffSonLTW()
  if ltw_son then
    ltw_son.LuaObjectScript.Disable()
  end
  TurnOffYSNP()
end
function Cal250Triptych_TurnOnSonLTW()
  if ltw_son then
    ltw_son.LuaObjectScript.Enable()
  end
end
function LTW_ToCaldera_Start()
  local stage = game.Level.GetVariable("FreyaLTWStage")
  if stage == 0 or stage > LTW_STAGES.STAGE_30 then
    return
  end
  DisableLTW()
  ltw_son = GameObjects.LTW_ToCaldera_Son
  ltw_freya = GameObjects.LTW_ToCaldera_Freya
  snp_son = GameObjects.SNP_ToCaldera_Son
  ltw_son.LuaObjectScript.Enable()
  ltw_freya.LuaObjectScript.Enable()
  snp_son.LuaObjectScript.Enable()
  GameObjects.CA_Observe_Forward_Up_SonCaveEnd.LuaObjectScript.Enable()
  CreateFreyaIdleSequence(GameObjects.Freya_Fake_CA_CaveEnd, "synchJoint")
end
function LTW_ToBridgePush_Start()
  local stage = game.Level.GetVariable("FreyaLTWStage")
  if stage == 0 or stage > LTW_STAGES.STAGE_40 then
    return
  end
  game.Level.SetVariable("FreyaLTWStage", LTW_STAGES.STAGE_40)
  DisableLTW()
  ltw_son = GameObjects.LTW_ToBridgePush_Son
  ltw_freya = GameObjects.LTW_ToBridgePush_Freya
  snp_son = GameObjects.SNP_ToBridgePush_Son
  ltw_son.LuaObjectScript.Enable()
  ltw_freya.LuaObjectScript.Enable()
  snp_son.LuaObjectScript.Enable()
  GameObjects.collision_Bridge:HideCollision()
  GameObjects.CA_Observe_Forward_Up_SonCaveEnd.LuaObjectScript.Disable()
  GameObjects.Freya_Fake_CA_CaveEnd:HideEntityVolume()
  if seq ~= nil then
    seq:Complete()
  end
  GameObjects.CA_Idle_BridgeStairsTop.LuaObjectScript.Enable()
  GameObjects.CA_Observe_Forward_Up_BridgeStairs.LuaObjectScript.Enable()
  CreateFreyaIdleSequence_TopOfBridgeStairs(GameObjects.Freya_Fake_CA_BridgeStairs, "synchJoint")
end
function LTW_ToBridgePush_SonDownStairs()
  TurnOffSonLTW()
  ltw_son = GameObjects.LTW_ToBridgePush_Son_DownStairs
  ltw_son.LuaObjectScript.Enable()
  GameObjects.CA_Idle_BridgeStairsTop.LuaObjectScript.Disable()
end
function LTW_ToBridgePush()
  local stage = game.Level.GetVariable("FreyaLTWStage")
  if stage == 0 or stage > LTW_STAGES.STAGE_45 then
    return
  end
  game.Level.SetVariable("FreyaLTWStage", LTW_STAGES.STAGE_45)
  DisableLTW()
  GameObjects.CA_Observe_Forward_Up_BridgeStairs.LuaObjectScript.Disable()
end
function BridgePushComplete()
  local stage = game.Level.GetVariable("FreyaLTWStage")
  if stage == 0 or stage > LTW_STAGES.STAGE_50 then
    return
  end
  game.Level.SetVariable("FreyaLTWStage", LTW_STAGES.STAGE_50)
  DisableLTW()
  local freya = LD.FindFreya()
  if freya then
    LTW_ToBridgePush_EndIdle()
  end
  local bookmarks = require("design.Bookmarks")
  local tableEntry = bookmarks["BOOKMARK_" .. "05_Caldera_020_PushComplete"]
  game.World.StoreCheckpointAndBookmark(tableEntry)
end
function LTW_ToBridgePush_EndIdle()
  CreateFreyaIdleSequence_NoEnter(GameObjects.FreyaSpawn_OutsideAirlock, "synchJoint")
end
function LTW_Airlock_Start()
  local stage = game.Level.GetVariable("FreyaLTWStage")
  if stage == 0 or stage > LTW_STAGES.STAGE_60 then
    return
  end
  game.Level.SetVariable("FreyaLTWStage", LTW_STAGES.STAGE_60)
  DisableLTW()
  GameObjects.BridgeCollision_Airlock:ShowCollision()
  ltw_son = GameObjects.LTW_Airlock_Son
  ltw_freya = GameObjects.LTW_Airlock_Freya
  ltw_son.LuaObjectScript.Enable()
  ltw_freya.LuaObjectScript.Enable()
  if seq ~= nil then
    seq:Complete()
  end
  local freya = ND.FindFreya()
  if freya then
    freya:SetAccelerationOverride(1.5)
  end
  game.AI.FindSon():SetAccelerationOverride(1.5)
end
function LTW_Airlock_Resume()
  local stage = game.Level.GetVariable("FreyaLTWStage")
  if stage == 0 or stage > LTW_STAGES.STAGE_60 then
    return
  end
  GameObjects.BridgeCollision_Airlock:HideCollision()
  ltw_son = GameObjects.LTW_AirlockResume_Son
  ltw_freya = GameObjects.LTW_AirlockResume_Freya
  ltw_son.LuaObjectScript.Enable()
  ltw_freya.LuaObjectScript.Enable()
  local freya = ND.FindFreya()
  if freya then
    freya:ClearAccelerationOverride()
  end
  game.AI.FindSon():ClearAccelerationOverride()
end
function LTW_EnterRealmTravel()
  local stage = game.Level.GetVariable("FreyaLTWStage")
  if stage == 0 or stage > LTW_STAGES.STAGE_70 then
    return
  end
  game.Level.SetVariable("FreyaLTWStage", LTW_STAGES.STAGE_70)
  DisableLTW()
end
function LTW_ExitRealmTravel()
  local stage = game.Level.GetVariable("FreyaLTWStage")
  if stage == 0 or stage > LTW_STAGES.STAGE_80 then
    return
  end
  game.Level.SetVariable("FreyaLTWStage", LTW_STAGES.STAGE_80)
  DisableLTW()
  CreateFreyaIdleSequence(GameObjects.Freya_Fake_CA_LeaveTravelRoom, "synchJoint")
end
function LTW_EnterAirlock_ToAlfheim_AndSetPriority()
  LTW_EnterAirlock_ToAlfheim()
  local freyaRef = ND.FindFreya()
  if freyaRef ~= nil then
    freyaRef:ModifyCreatureMotion({MovementPriority = 1000, UnmovableByCreature = true})
  end
end
function LTW_EnterAirlock_ToAlfheim()
  game.Level.SetVariable("FreyaLTWStage", LTW_STAGES.STAGE_90)
  GameObjects.Freya_Fake_CA_LeaveTravelRoom:HideEntityVolume()
  if seq ~= nil then
    seq:Complete()
  end
end
function LTW_DONE()
  game.Level.SetVariable("FreyaLTWStage", LTW_STAGES.STAGE_DONE)
  son:CallScript("LuaHook_ToggleSlowdownStops", true)
end
function CreateFreyaIdleSequence(syncAndZoneObj, synchJointName)
  if freActor then
    freActor = nil
  end
  freActor = actor.Actor.New("Freya", ND.FindFreya)
  seq = ND.CreateCineSequence(thisLevel, syncAndZoneObj, "Freya Idle Sequence")
  seq:WaitForActorInZone(freActor, syncAndZoneObj)
  seq:ActorForceApproachAndWait(freActor, {
    Branch = "BRA_CartButtonEnter",
    ReferenceJoint = synchJointName,
    speed = ND.FreyaWalkSpeed,
    stop = false,
    foot = game.Creature.Foot.kLeft,
    radius = ND.ArrivalRadius
  })
  seq:ActorSync(freActor, {
    Branch = "BRA_CartButtonEnter",
    ReferenceJoint = synchJointName
  })
  seq:WaitForSyncStart(freActor:GetCreature())
  seq:StopPuppetingActor(freActor)
  seq:StartSequence()
end
function CreateFreyaIdleSequence_NoEnter(syncObj, synchJointName)
  if freActor then
    freActor = nil
  end
  freActor = actor.Actor.New("Freya", ND.FindFreya)
  seq = ND.CreateCineSequence(thisLevel, syncObj, "Freya Idle Sequence - No Enter")
  seq:ActorSync(freActor, {
    Branch = "BRA_CartButtonIdle",
    ReferenceJoint = synchJointName
  })
  seq:WaitForSyncStart(freActor:GetCreature())
  seq:StopPuppetingActor(freActor)
  seq:StartSequence()
end
function CreateFreyaIdleSequence_TopOfBridgeStairs(syncAndZoneObj, synchJointName)
  if freActor then
    freActor = nil
  end
  freActor = actor.Actor.New("Freya", ND.FindFreya)
  seq = ND.CreateCineSequence(thisLevel, syncAndZoneObj, "Freya Idle Sequence - Auto Exit")
  seq:WaitForActorInZone(freActor, syncAndZoneObj)
  seq:Do(function()
    GameObjects.Freya_Fake_CA_BridgeStairs:HideEntityVolume()
  end)
  seq:ActorForceApproachAndWait(freActor, {
    Branch = "BRA_CartButtonEnter_AutoExit",
    ReferenceJoint = synchJointName,
    speed = ND.FreyaWalkSpeed,
    stop = false,
    foot = game.Creature.Foot.kLeft,
    radius = ND.ArrivalRadius
  })
  seq:ActorSync(freActor, {
    Branch = "BRA_CartButtonEnter_AutoExit",
    ReferenceJoint = synchJointName
  })
  seq:WaitForSyncStart(freActor:GetCreature())
  seq:StopPuppetingActor(freActor)
  seq:WaitForActorPlayingMove(freActor, "MOV_CartButtonEnter_AutoExit")
  seq:WaitUntilActorAnimPastPercentage(freActor, 0.5)
  seq:Do(function()
    game.Audio.PlayBanter("MagicBowstring")
  end)
  seq:WaitForActorPlayingMove(freActor, "MOV_CartButtonGesture01_AutoExit")
  seq:WaitUntilActorAnimPastPercentage(freActor, 0.5)
  seq:Do(LTW_ToBridgePush_SonDownStairs)
  seq:StartSequence()
end
