local LD = require("design.LevelDesignLibrary")
local ND = require("design.NarrativeDesignLibrary")
local TUT = require("game.GlobalTutorials")
local DL = require("design.DesignerLibrary")
local monitors = require("level.MonitorLibrary")
local timer = require("level.timer")
local actorlib = require("narrative.actor")
local color = require("core.color")
local uiCalls = require("ui.uicalls")
local thisLevel, player, baldurDragon, baldur
local stage = 0
local heroPuppeteer, baldurDragonPup
local debugSkipped = false
local fightTriggered = false
local stopFrenzyRun = false
local frenzySeq
local fromCheckpoint = false
local cameraScreenShake
local mmaTutorialPhase = 0
local mmaTutorialEnabled = true
function OnScriptLoaded(level)
  thisLevel = level
  player = game.Player.FindPlayer()
  if game.Wallets.HasResource("HERO", "Blades") == false then
    game.Wallets.AddResource("HERO", "Blades", 1, "NO_TELEMETRY")
  end
  DL.HideLevelObject(thisLevel, "fx_jumpoff_clouds")
  game.Audio.StartMusicMaster("SND_MX_PEAK_baldur2_master")
end
function OnStart(level)
  if game.Level.GetVariable("CompletedCineNumber") < 490 then
    LD.RegisterForVariableUpdate(level, "DragonArrivalTriggered", {
      immediateFn = StartDragonRide,
      fn = StartDragonRide
    })
  end
end
local SetupTutorialMMA = function()
  mmaTutorialPhase = 1
  if baldur:HasMarker("MMA_Tutorial") == false then
    baldur:AddMarker("MMA_Tutorial")
  end
  if player:HasMarker("MMA_TutorialBegin") == false then
    player:AddMarker("MMA_TutorialBegin")
  end
end
local CleanTutorialMMA = function()
  if baldur:HasMarker("MMA_Tutorial") then
    baldur:RemoveMarker("MMA_Tutorial")
  end
  if player:HasMarker("MMA_TutorialBegin") then
    player:RemoveMarker("MMA_TutorialBegin")
  end
end
local UpdateTutorialMMA = function()
  if player:HasMarker("MMA_TutorialBegin") == true and baldur:IsPlayingMove("MOV_MMA_Defense_AttackTutorial") then
    player:RemoveMarker("MMA_TutorialBegin")
  end
  if mmaTutorialPhase == 1 then
    uiCalls.SendSidebarDesignerMessage({
      Text = 18056,
      AdvanceType = uiCalls.msgParam.INFINITE_TIMER,
      Critical = true
    })
    mmaTutorialPhase = mmaTutorialPhase + 1
  elseif mmaTutorialPhase == 2 then
    if DL.CheckCreatureContext(player:GetContext(), "DEFENDING") then
      baldur:TriggerMoveEvent("LE_MMABlockTutorialDone")
    end
    if baldur:IsPlayingMove("MOV_MMA_Defense_DodgeTutorial") then
      uiCalls.SendSidebarDesignerMessage({
        Text = 18057,
        AdvanceType = uiCalls.msgParam.INFINITE_TIMER,
        Critical = true
      })
      mmaTutorialPhase = mmaTutorialPhase + 1
    end
  elseif mmaTutorialPhase == 3 then
    if baldur:IsPlayingMove("MOV_MMA_Defense_DodgeTutorial2") then
      uiCalls.SendSidebarDesignerMessage({
        Text = 24790,
        AdvanceType = uiCalls.msgParam.INFINITE_TIMER,
        Critical = true
      })
      mmaTutorialPhase = mmaTutorialPhase + 1
    end
  elseif mmaTutorialPhase == 4 and baldur:IsPlayingMove("MOV_MMA_Defense_AttackTutorial") then
    uiCalls.SendSidebarDesignerMessage({
      Text = 18165,
      MessageVariant = uiCalls.msgParam.SIDEBAR_MEDIUM,
      AdvanceType = uiCalls.msgParam.INFINITE_TIMER,
      Critical = true
    })
    mmaTutorialPhase = mmaTutorialPhase + 1
  end
  if baldur:HasMarker("React") then
    mmaTutorialPhase = 99
    uiCalls.UI_Event_TurnOffDesignerMessage()
  end
end
function OnUpdate(level)
  if game.World.IsInsideCameraZone(player.WorldPosition, "CamZone_Peak800_SprintSequence") and player:HasMarker("Sprinting") then
    game.Camera.SubmitCameraByName("PLYR_Sprint_HengeDisruption")
  end
  if stage == 2 then
    game.Camera.SubmitCameraByName("PLYR_MMA_010_Peak800")
    if player:HasMarker("CAMERAPUSH") then
      game.Camera.SubmitCameraByName("PLYR_MMA_010_Zoom_Peak800")
    end
  elseif stage == 4 then
    game.Camera.SubmitCameraByName("PLYR_MMA_020_Peak800")
    if player:HasMarker("CAMERAPUSH") then
      game.Camera.SubmitCameraByName("PLYR_MMA_020_Zoom_Peak800")
    end
    if mmaTutorialEnabled then
      UpdateTutorialMMA()
    end
  elseif stage == 6 then
    game.Camera.SubmitCameraByName("PLYR_MMA_030_Peak800")
    if player:HasMarker("CAMERAPUSH") then
      game.Camera.SubmitCameraByName("PLYR_MMA_030_Zoom_Peak800")
    end
  end
  if baldurDragon ~= nil and baldur ~= nil then
    DL.DrawTextOnPlayer("Drag Pos: " .. baldurDragon:GetWorldPosition().x .. " - " .. baldurDragon:GetWorldPosition().y .. " - " .. baldurDragon:GetWorldPosition().z)
    DL.DrawTextOnPlayer([[

Drag Rot: ]] .. baldurDragon:GetWorldForward().x .. " - " .. baldurDragon:GetWorldForward().y .. " - " .. baldurDragon:GetWorldForward().z)
    CheckTransitions()
  end
end
function SpawnDragon()
  if FindDragon() == nil then
    baldurDragon = GameObjects.BaldurDragon00_SpawnPoint.LuaObjectScript.SpawnEnemy()
  else
    baldurDragon = FindDragon()
  end
  return baldurDragon
end
function SpawnBaldur()
  if baldur == nil and ND.FindBaldur() == nil then
    baldur = GameObjects.BaldurSpawner.LuaObjectScript.SpawnEnemy()
  elseif baldur == nil and ND.FindBaldur() ~= nil then
    baldur = ND.FindBaldur()
  end
  baldur:AddMarker("Baldur")
  baldur:AddMarker("DragonEncounter")
  baldur:AddMarker("MMA_Dragon")
  return baldur
end
function SetBaldur(bldrRef)
  baldur = bldrRef
end
function FindDragon()
  local objArray = game.World.FindGameObjectsByMarker("baldurdragon00")
  for _, obj in ipairs(objArray) do
    if obj:GetCreature() ~= nil and obj:GetCreature():GetAI() ~= nil then
      return obj:GetCreature():GetAI()
    end
  end
  return nil
end
function StartDragonRide()
  if game.Level.GetVariable("CAL_OnDragonRide") ~= true then
    SpawnDragon()
    SpawnBaldur()
    local availabilityState = {AvailableForCombat = false}
    game.AI.FindSon():SetNewAvailabilityRequest("LevelDesignScript", availabilityState)
    StartLevelTimer(0.1, function()
      fightTriggered = true
      stage = 0
      StageIncrement()
    end)
  end
end
function StageDecrement()
  if 0 < stage then
    stage = stage - 1
    StageSetupDelayed()
  end
end
function StageIncrement()
  if stage < 8 then
    stage = stage + 1
    StageSetup()
  end
end
function StageIncrementDelayed()
  if stage < 8 then
    stage = stage + 1
    StageSetupDelayed()
  end
end
function StageIncrementDebug()
  if player.Pad.L1Down == true and fightTriggered == true then
    if player.Pad.L2Down == true then
      stage = 7
    end
    StageIncrementDelayed()
  end
end
function StageDecrementDebug()
  if player.Pad.L1Down == true and fightTriggered == true then
    StageDecrement()
  end
end
function StageReplayDebug()
  if player.Pad.L1Down == true and fightTriggered == true then
    StageSetupDelayed()
  end
end
function StageSetupDelayed()
  debugSkipped = true
  SpawnDragon()
  SpawnBaldur()
  baldur:MeterSetValue("Health", 800)
  player:TriggerMoveEvent("LE_ForceIdle")
  baldur:TriggerMoveEvent("LE_ForceIdle")
  baldurDragon:TriggerMoveEvent("LE_ForceIdle")
  timer.StartLevelTimer(0.1, StageSetup)
end
function SetupDragonLoopPosition(posIndex)
  baldur:RemoveMarker("DragonEncounter1")
  baldur:RemoveMarker("DragonEncounter2")
  baldur:RemoveMarker("DragonEncounter3")
  DL.WarpCreature(baldurDragon, thisLevel, "Warp_FightBubbleDragon")
  local dragonPos = DL.GetMarkerPosition(thisLevel, "Warp_FightBubbleDragon")
  local dragonRot = DL.GetMarkerRotation(thisLevel, "Warp_FightBubbleDragon")
  if posIndex == 1 then
    TUT.Peak800_BaldurMMAOffense_Tutorial_Bottom()
    baldur:AddMarker("DragonEncounter1")
    baldurDragon:TriggerMoveEvent("LE_DragonLoopTail")
    if player:IsPlayingMove("MOV_MMA_Defense_EnterTail") == false then
      player:TriggerMoveEvent("LE_MMATail")
    end
    DL.WarpCreature(player, thisLevel, "Warp_MMA_Tail")
    DL.WarpCreature(baldur, thisLevel, "Warp_MMA_Tail_Baldur")
  elseif posIndex == 2 then
    if mmaTutorialEnabled then
      SetupTutorialMMA()
    else
      TUT.Peak800_BaldurMMADefense_Tutorial()
    end
    baldur:AddMarker("DragonEncounter2")
    baldurDragon:TriggerMoveEvent("LE_DragonLoopBack")
    if player:IsPlayingMove("MOV_MMA_Defense_EnterBack") == false then
      player:TriggerMoveEvent("LE_MMABack")
    end
    DL.WarpCreature(player, thisLevel, "Warp_MMA_Back")
    DL.WarpCreature(baldur, thisLevel, "Warp_MMA_Back_Baldur")
  elseif posIndex == 3 then
    baldur:AddMarker("DragonEncounter3")
    baldurDragon:TriggerMoveEvent("LE_DragonLoopNeck")
    if player:IsPlayingMove("MOV_MMA_Defense_EnterNeck") == false then
      player:TriggerMoveEvent("LE_MMANeck")
    end
    DL.WarpCreature(player, thisLevel, "Warp_MMA_Neck")
    DL.WarpCreature(baldur, thisLevel, "Warp_MMA_Neck_Baldur")
    game.AI.FindSon():Warp(engine.Vector.New(-625.831, 966.513, 1284.202), 180)
  end
end
local kratosActor = actorlib.Actor.New("Kratos", game.Player.FindPlayer)
local sonActor = actorlib.Actor.New("Son", game.AI.FindSon)
local baldurActor = actorlib.Actor.New("Baldur", function()
  return baldur
end)
local dragonActor = actorlib.Actor.New("BaldurDragon", function()
  return baldurDragon
end)
local fogFXPlayed = false
function StageFirstInit()
  DL.ShowLevelObject(thisLevel, "fx_jumpoff_clouds")
  baldur:CallScript("SetNonhostile")
  LD.SetEntityVariable("CAL_OnDragonRide", true)
end
function StageSetup()
  baldur:MeterSetValue("MMA_Counter", 0)
  baldur:MeterSetValue("MMA_Choke", 0)
  uiCalls.UI_Event_TurnOffDesignerMessage()
  if player:HasMarker("MMA_ReadyDragon") then
    player:RemoveMarker("MMA_ReadyDragon")
  end
  if player:HasMarker("DragonEncounter") == false then
    player:AddMarker("DragonEncounter")
  end
  baldur:MeterSetValue("Health", 800)
  local peak740 = game.FindLevel("peak740_SummitPeak")
  if peak740 ~= nil then
    peak740:CallScript("HideDeathplanes")
  end
  if fromCheckpoint == true and stage == 1 then
    StageFirstInit()
    stage = 2
  end
  if stage == 1 then
    StageFirstInit()
  elseif stage == 2 then
    baldur:CallScript("SetHostile")
    SetupDragonLoopPosition(1)
  elseif stage == 3 then
    baldur:CallScript("SetNonhostile")
    baldurDragon:TriggerMoveEvent("LE_DragonTailTransition")
  elseif stage == 4 then
    baldur:CallScript("SetHostile")
    SetupDragonLoopPosition(2)
  elseif stage == 5 then
    if mmaTutorialEnabled then
      CleanTutorialMMA()
    end
    baldur:CallScript("SetNonhostile")
    baldurDragon:TriggerMoveEvent("LE_DragonBackTransition")
  elseif stage == 6 then
    baldur:CallScript("SetHostile")
    SetupDragonLoopPosition(3)
  elseif stage == 7 then
    DL.ResetObjectAnimation(thisLevel, "fx_transition_peak800")
    fogFXPlayed = false
    player:RemoveMarker("DragonEncounter")
    local sequence = LD.CreateCineSequence(thisLevel, GameObjects.DragonWinSynch, "DragonKill")
    sequence:Do(function()
      baldurDragon:TriggerMoveEvent("LE_DragonKill")
    end)
    sequence:WaitSeconds(0.1)
    sequence:WaitForFunctionTrue(function()
      return player:IsPlayingMove("MOV_BaldurDragonKill") and player:GetActiveMovePercent() > 0.6
    end)
    sequence:Do(function()
      GameObjects.Peak800_Banter.LuaObjectScript.BaldurRoar_Banter()
    end)
    sequence:WaitForFunctionTrue(function()
      if player:IsPlayingMove("MOV_BaldurDragonKill") and player:GetActiveMovePercent() > 0.93 and fogFXPlayed == false then
        DL.PlayObjectAnimation(thisLevel, "fx_transition_peak800")
        fogFXPlayed = true
      end
      return player:IsPlayingMove("MOV_BaldurDragonKill") == false
    end)
    sequence:StopPuppetingActor(kratosActor)
    sequence:StopPuppetingActor(sonActor)
    sequence:StopPuppetingActor(baldurActor)
    sequence:StopPuppetingActor(dragonActor)
    sequence:StartSequence()
  elseif stage == 8 then
    LD.Trigger_DragonArrival()
    local cal100 = game.FindLevel("Cal100_Hub")
    if cal100 ~= nil then
      cal100:CallScript("ShowHengeDisruptionSprintCamera")
    end
    local sequence = LD.CreateCineSequence(thisLevel, GameObjects.DragonWinSynch, "DragonWin")
    sequence:ActorSync(kratosActor, {
      Slaves = {
        {Actor = sonActor},
        {Actor = baldurActor},
        {Actor = dragonActor}
      },
      Branch = "BRA_BaldurDragonExit",
      ReferenceJoint = "csBaldurDragonKillJoint"
    })
    sequence:Do(StartFrenzyRun)
    sequence:WaitForActorFinishMove(kratosActor, "MOV_BaldurDragonExit")
    sequence:StopPuppetingActor(sonActor)
    sequence:StopPuppetingActor(baldurActor)
    sequence:StopPuppetingActor(dragonActor)
    sequence:StartSequence()
  end
  debugSkipped = false
end
function StartFrenzyRun()
  frenzySeq = LD.CreateCineSequence(thisLevel, GameObjects.DragonWinSynch, "DragonRun")
  if not stopFrenzyRun then
    frenzySeq:ActorForceApproachAndWait(kratosActor, {
      pos = GameObjects.DragonWinSynch:GetWorldJointPosition(GameObjects.DragonWinSynch:GetJointIndex("AirlockDoorLocation")),
      speed = 6,
      stop = false,
      radius = ND.RunArrivalRadius,
      weapon_state = "bare"
    })
  end
  frenzySeq:StopPuppetingActor(kratosActor)
  frenzySeq:StartSequence()
end
function StopFrenzyRun()
  local cal100 = game.FindLevel("Cal100_Hub")
  if cal100 ~= nil then
    cal100:CallScript("HideHengeDisruptionSprintCamera")
  end
  stopFrenzyRun = true
  if frenzySeq ~= nil then
    frenzySeq:Complete()
  end
end
function RestartDragonRide()
  fromCheckpoint = true
  kratosActor = actorlib.Actor.New("Kratos", game.Player.FindPlayer)
  sonActor = actorlib.Actor.New("Son", game.AI.FindSon)
  baldurActor = actorlib.Actor.New("Baldur")
  dragonActor = actorlib.Actor.New("BaldurDragon")
  baldurActor:SetSpawnFunction(SpawnBaldur)
  dragonActor:SetSpawnFunction(SpawnDragon)
  local sequence = LD.CreateCineSequence(thisLevel, GameObjects.DragonRideSynch, "DragonRide")
  local actorTable = {
    {Actor = sonActor},
    {Actor = baldurActor}
  }
  sequence:SpawnActorAndWait(baldurActor)
  sequence:SpawnActorAndWait(dragonActor)
  sequence:Do(function()
    StartDragonRide()
  end)
  sequence:StopPuppetingActor(kratosActor)
  sequence:StopPuppetingActor(sonActor)
  sequence:StopPuppetingActor(baldurActor)
  sequence:StartSequence()
  LD.SetEntityVariable("CAL_OnDragonRide", false)
end
function CheckTransitions()
  engine.DrawText2D("Stage: " .. stage, 600, 100, color.yellow)
  if stage == 6 then
    baldur:MeterSetValue("MMA_Counter", 0)
  end
  if player:IsPlayingMove("MOV_TriggerNextMove") or player:IsPlayingMove("MOV_TriggerNextMoveInstant") or baldur:IsPlayingMove("MOV_TriggerNextMove") or baldurDragon:IsPlayingMove("MOV_TriggerNextMove") then
    StageIncrement()
    player:TriggerMoveEvent("kLETransitionExecuted")
    baldur:TriggerMoveEvent("kLETransitionExecuted")
    baldurDragon:TriggerMoveEvent("kLETransitionExecuted")
  end
  if debugSkipped == false then
    if stage == 1 and player:IsPlayingMove("MOV_MMA_Defense_EnterTail") then
      StageIncrement()
    elseif stage == 2 and baldur:GetHitPoints() < 750 then
      if player:HasMarker("MMA_ReadyDragon") == false then
        player:AddMarker("MMA_ReadyDragon")
      elseif player:IsPlayingMove("MOV_MMA_Offense_Idle_R") or player:IsPlayingMove("MOV_MMA_Offense_Idle_L") then
        StageIncrement()
      end
    elseif stage == 3 and player:IsPlayingMove("MOV_MMA_Defense_EnterBack") then
      StageIncrement()
    elseif stage == 4 and baldur:GetHitPoints() < 700 then
      if player:HasMarker("MMA_ReadyDragon") == false then
        player:AddMarker("MMA_ReadyDragon")
      elseif baldur:HasMarker("React") == false and player:HasMarker("MMA_ReadyDragon") then
        StageIncrement()
      end
    elseif stage == 5 and player:IsPlayingMove("MOV_MMA_Defense_EnterNeck") then
      StageIncrement()
    elseif stage == 6 and baldur:GetHitPoints() < 750 then
      if player:HasMarker("MMA_ReadyDragon") == false then
        player:AddMarker("MMA_ReadyDragon")
      elseif player:IsPlayingMove("MOV_MMA_Offense_Idle_R") or player:IsPlayingMove("MOV_MMA_Offense_Idle_L") then
        StageIncrement()
      end
    elseif stage == 7 and (player:IsPlayingMove("MOV_BaldurDragonExit") or player:IsPlayingMove("MOV_BaldurDragonKill") and 1 <= player:GetActiveMovePercent()) then
      StageIncrement()
    end
  end
end
