local classlib = require("core.class")
local tablex = require("core.tablex")
local consts = require("ui.consts")
local fsm = require("ui.fsm")
local messageRequest = require("ui.messageRequest")
local tutorialConsts = require("ui.tutorialConsts")
local tutorials = require("ui.tutorials")
local tutorialUtil = require("ui.tutorialUtil")
local uiCalls = require("ui.uicalls")
local util = require("ui.util")
local UI = game.UI
local Blender = game.Blender
local TutorialMode = classlib.Class("TutorialMode", fsm.UIState)
local TMOff = TutorialMode:StateClass("TMOff", fsm.UIState)
local TMOn = TutorialMode:StateClass("TMOn", fsm.UIState)
local TMAdvance = TutorialMode:StateClass("TMAdvance", fsm.UIState)
local tutorialMode = TutorialMode.New("tutorialMode", {
  TMOff,
  TMOn,
  {TMAdvance}
})
function TutorialMode:Setup()
  self.inputAvailable = false
  self.tutorial = nil
  self.isL2Pressed = false
  self.isR2Pressed = false
  self.prevCenterOffset = {}
  tutorialUtil.SetCurrentTutorialStep(nil)
  self.promptFadeInTime = 0.2
  self.promptFadeOutTime = 0.2
  self.promptAnimSpeed = 0
  self.messageGOs = {
    [uiCalls.msgParam.PAUSE_TUTORIAL_SMALL] = util.GetUiObjByName("PauseTutorialMessage_Small"),
    [uiCalls.msgParam.PAUSE_TUTORIAL_LARGE] = util.GetUiObjByName("PauseTutorialMessage")
  }
  tutorialUtil.RegisterDesaturationObject("PauseTutorialMessage_Small", self.messageGOs[uiCalls.msgParam.PAUSE_TUTORIAL_SMALL])
  tutorialUtil.RegisterDesaturationObject("PauseTutorialMessage", self.messageGOs[uiCalls.msgParam.PAUSE_TUTORIAL_LARGE])
end
function TutorialMode:Enter()
  self:WantPadEvents(false)
  self:TurnOff()
  self:StartTimer("TMInitializationTimer", consts.SingleFrameDelayTime, function()
    self.inputAvailable = true
    if not tutorialUtil.IsStepQueueEmpty() then
      self:BeginTutorial()
    end
  end)
end
function TutorialMode:TurnOff()
  self:Goto("TMOff")
end
TutorialMode.EVT_GAME_OVER = TutorialMode.TurnOff
TutorialMode.EVT_Restart = TutorialMode.TurnOff
function TutorialMode:BeginTutorial()
  if not tutorialUtil.CurrentlyShowingStep() and self.inputAvailable then
    local firstStep = tutorialUtil.PeekStep()
    self.prevCenterOffset = {}
    if firstStep.StartBlender ~= false then
      Blender.Start("FSE_ColorCorrection_Desaturate")
      Blender.Start("FSE_ColorCorrection_Desaturate_UI")
    end
    self:Goto("TMOn")
  end
end
function TutorialMode:EndTutorial()
  Blender.Stop("FSE_ColorCorrection_Desaturate")
  Blender.Stop("FSE_ColorCorrection_Desaturate_UI")
  tutorialUtil.ResetDesaturationAll()
end
function TutorialMode:GetNextStep()
  local currentTutorialStep = tutorialUtil.DequeueStep()
  tutorialUtil.SetCurrentTutorialStep(currentTutorialStep)
  local currentMessage = self:SetupMessage(currentTutorialStep)
  tutorialUtil.SetCurrentMessage(currentMessage)
  tutorialUtil.SetDesaturationAll()
end
function TutorialMode:SetupMessage(tutorialStep)
  local messageArgs = tutorialStep.MessageArgs
  local conditionArgs = tutorialStep.ConditionArgs
  local footerButtonInfo = tutorialUtil.CreateFooterButtonInfo(tutorialStep)
  return messageRequest.MessageRequest.New(self, {
    MessageObject = self.messageGOs[messageArgs.MessageType],
    HeaderMessage = messageArgs.HeaderMessage,
    BodyMessage = messageArgs.BodyMessage,
    Time = 0.5,
    MessageDelay = messageArgs.MessageDelay,
    ExitDelay = messageArgs.ExitDelay,
    AdvanceType = conditionArgs.AdvanceType,
    MessageType = uiCalls.msgParam.MESSAGE_TUTORIAL,
    AnimSpeed = self.promptAnimSpeed,
    FadeInTime = self.promptFadeInTime,
    FadeOutTIme = self.promptFadeOutTime,
    UnpauseWhenComplete = messageArgs.UnpauseWhenComplete,
    FooterButtonInfo = footerButtonInfo,
    AdvanceToNextMessage = function()
      self:AdvanceToNextStep()
    end,
    OnExitTransitionBegin = function(currentMessage)
      self:OnExitTransitionBegin(currentMessage)
    end,
    UseUIAccessibilityScaling = true
  })
end
function TutorialMode:OnExitTransitionBegin(currentMessage)
  local fadeGOs = {
    currentMessage:get_goTextObjects()
  }
  currentMessage:AnimateOut(fadeGOs, self:WillMessageMove())
  self:UpdatePreviousCenterOffset()
end
function TutorialMode:OnMessageComplete()
  if not tutorialUtil.IsStepQueueEmpty() then
    self:Goto("TMOn")
  else
    self:EndTutorial()
  end
end
function TutorialMode:ClearAllMessages()
  if self:HaveTimer("MessageDelayTimer") then
    self:StopTimer("MessageDelayTimer")
  end
  if self:HaveTimer("AdvanceHelperTimer") then
    self:StopTimer("AdvanceHelperTimer")
  end
  if self:HaveTimer("TMTimer") then
    self:StopTimer("TMTimer")
  end
  tutorialUtil.SetCurrentTutorialStep(nil)
  tutorialUtil.SetCurrentMessage(nil)
  tutorialUtil.ClearStepQueue()
  self:AdvanceToNextStep()
end
function TutorialMode:AdvanceToNextStep()
  self:Goto("TMOff")
end
function TutorialMode:HandleMessageDelay()
  local currentMessage = tutorialUtil.GetCurrentMessage()
  local messageDelay = currentMessage:get_messageDelay()
  if messageDelay == 0 then
    self:DisplayMessage()
  else
    self:StartTimer("MessageDelayTimer", messageDelay, function()
      self:DisplayMessage()
    end)
  end
end
function TutorialMode:HandleMessageAdvance()
  local currentMessage = tutorialUtil.GetCurrentMessage()
  local messageTime = currentMessage:get_time()
  local advanceType = currentMessage:get_advanceType()
  if advanceType == uiCalls.msgParam.ADVANCE_PRESS then
    local fullDelayTime = currentMessage:get_messageDelay() + messageTime
    if fullDelayTime == 0 then
      self:Goto("TMAdvance")
    else
      self:StartTimer("AdvanceHelperTimer", fullDelayTime, function()
        self:Goto("TMAdvance")
      end)
    end
  elseif advanceType == uiCalls.msgParam.ADVANCE_HOLD then
    assert(false, "TutorialMode does not handle ADVANCE_HOLD advanceType messages yet!")
  elseif advanceType == uiCalls.msgParam.ADVANCE_TIMER then
    assert(messageTime ~= 0, "TutorialMode Message attempted to advance on timer with time of zero!")
    self:StartTimer("TMTimer", messageTime, function()
      self:Goto("TMOff")
    end)
  end
end
function TutorialMode:HandleMessageExit()
  local currentMessage = tutorialUtil.GetCurrentMessage()
  if currentMessage ~= nil then
    currentMessage:OnExitTransitionBegin()
    local exitDelay = currentMessage:get_exitDelay()
    if exitDelay == 0 then
      self:ClearScreen()
    else
      self:StartTimer("TMTimer", exitDelay, function()
        self:ClearScreen()
      end)
    end
  else
    self:ClearScreen()
  end
end
function TutorialMode:ClearScreen()
  for _, goMessage in pairs(self.messageGOs) do
    goMessage:Hide()
  end
  tutorialUtil.SetCurrentTutorialStep(nil)
  tutorialUtil.SetCurrentMessage(nil)
  self:OnMessageComplete()
end
function TutorialMode:DisplayMessage()
  local currentMessage = tutorialUtil.GetCurrentMessage()
  local messageType = currentMessage:get_messageType()
  local goItemCardMessageChild = currentMessage:get_goMessageRequestChild()
  local fadeGOs = {
    goItemCardMessageChild:FindSingleGOByName("TextObjects")
  }
  local messageMoved = self:DidMessageMove()
  assert(messageType == uiCalls.msgParam.MESSAGE_TUTORIAL, "TutorialMOde attempted to call DisplayMessage with a message of type: " .. tostring(messageType))
  self:SetTutorialMessage(currentMessage)
  if messageMoved == true then
    tutorialUtil.SetPosition(currentMessage)
  end
  currentMessage:Show()
  currentMessage:AnimateIn(fadeGOs, messageMoved)
end
function TutorialMode:SetTutorialMessage(messageRequest)
  assert(messageRequest ~= nil)
  local thHeader = messageRequest:GetTextHandle("Header")
  messageRequest:SetText(thHeader, messageRequest:get_headerMessage())
  local thBody = messageRequest:GetTextHandle("Body")
  messageRequest:SetText(thBody, messageRequest:get_bodyMessage())
  UI.SetTextIsUIMacro(thBody)
end
function TutorialMode:CanMoveMessage()
  return self.isL2Pressed and self.isR2Pressed
end
function TutorialMode:MoveMessage(xOffset, yOffset)
  if tutorialUtil.CurrentlyShowingStep() and self:CanMoveMessage() then
    tutorialUtil.UpdateCenterOffset(xOffset, yOffset)
    self:PadRepeat(30)
  end
end
function TutorialMode:DidMessageMove()
  local currentTutorialStep = tutorialUtil.GetCurrentTutorialStep()
  local currentStepCenterOffset = tutorialUtil.GetCenterOffset(currentTutorialStep)
  return currentStepCenterOffset[1] ~= self.prevCenterOffset[1] or currentStepCenterOffset[2] ~= self.prevCenterOffset[2]
end
function TutorialMode:WillMessageMove()
  local willMessageMove = true
  local currentTutorialStep = tutorialUtil.GetCurrentTutorialStep()
  local currentStepCenterOffset = tutorialUtil.GetCenterOffset(currentTutorialStep)
  local nextTutorialStep = tutorialUtil.PeekStep()
  if nextTutorialStep ~= nil then
    local nextStepCenterOffset = tutorialUtil.GetCenterOffset(nextTutorialStep)
    willMessageMove = currentStepCenterOffset[1] ~= nextStepCenterOffset[1] or currentStepCenterOffset[2] ~= nextStepCenterOffset[2]
  end
  return willMessageMove
end
function TutorialMode:UpdatePreviousCenterOffset()
  local currentTutorialStep = tutorialUtil.GetCurrentTutorialStep()
  local currentStepCenterOffset = tutorialUtil.GetCenterOffset(currentTutorialStep)
  self.prevCenterOffset[1] = currentStepCenterOffset[1]
  self.prevCenterOffset[2] = currentStepCenterOffset[2]
end
function TutorialMode:EVT_SETUP_TUTORIAL(tutorialName)
  assert(not util.IsStringNilOrEmpty(tutorialName), "No tutorial name pased in to EVT_SETUP_TUTORIAL")
  tutorialUtil.SetupTutorialStepQueue(tutorials, tutorialName)
end
function TutorialMode:EVT_BEGIN_TUTORIAL()
  self:BeginTutorial()
end
function TutorialMode:EVT_SETUP_AND_BEGIN_TUTORIAL(tutorialResource, tutorialName)
  assert(not util.IsStringNilOrEmpty(tutorialResource), "No tutorial resource name pased in to EVT_SETUP_AND_BEGIN_TUTORIAL")
  assert(not util.IsStringNilOrEmpty(tutorialName), "No tutorial name pased in to EVT_SETUP_AND_BEGIN_TUTORIAL")
  tutorialUtil.SetupAndBeginTutorial(self, tutorials, tutorialResource, tutorialName)
end
function TutorialMode:EVT_L2_Press()
  if tutorialUtil.CurrentlyShowingStep() and not self.isL2Pressed then
    self.isL2Pressed = true
    if self:CanMoveMessage() then
      tutorialUtil.SetPositionInfoText()
    end
  end
end
function TutorialMode:EVT_L2_Release()
  local couldMoveMessage = self:CanMoveMessage()
  self.isL2Pressed = false
  if couldMoveMessage and not self:CanMoveMessage() then
    local currentMessage = tutorialUtil.GetCurrentMessage()
    self:SetTutorialMessage(currentMessage)
  end
end
function TutorialMode:EVT_R2_Press()
  if tutorialUtil.CurrentlyShowingStep() and not self.isR2Pressed then
    self.isR2Pressed = true
    if self:CanMoveMessage() then
      tutorialUtil.SetPositionInfoText()
    end
  end
end
function TutorialMode:EVT_R2_Release()
  local couldMoveMessage = self:CanMoveMessage()
  self.isR2Pressed = false
  if couldMoveMessage and not self:CanMoveMessage() then
    local currentMessage = tutorialUtil.GetCurrentMessage()
    self:SetTutorialMessage(currentMessage)
  end
end
function TutorialMode:EVT_Up_Press()
  self:MoveMessage(0, 0.01)
end
function TutorialMode:EVT_Down_Press()
  self:MoveMessage(0, -0.01)
end
function TutorialMode:EVT_Left_Press()
  self:MoveMessage(-0.01, 0)
end
function TutorialMode:EVT_Right_Press()
  self:MoveMessage(0.01, 0)
end
function TutorialMode:EVT_LeftStick_Up()
  self:MoveMessage(0, 0.1)
end
function TutorialMode:EVT_LeftStick_Down()
  self:MoveMessage(0, -0.1)
end
function TutorialMode:EVT_LeftStick_Left()
  self:MoveMessage(-0.1, 0)
end
function TutorialMode:EVT_LeftStick_Right()
  self:MoveMessage(0.1, 0)
end
function TMOff:Setup()
  self.initialized = false
  self.tutorialMode = self:GetState("tutorialMode")
end
function TMOff:Enter()
  if self.initialized then
    self.tutorialMode:HandleMessageExit()
  else
    self.initialized = true
  end
end
function TMOff:Exit()
end
function TMOn:Setup()
  self.tutorialMode = self:GetState("tutorialMode")
end
function TMOn:Enter()
  self.tutorialMode:GetNextStep()
  self.tutorialMode:HandleMessageDelay()
  self.tutorialMode:HandleMessageAdvance()
end
function TMOn:Exit()
end
function TMAdvance:Setup()
  self.tutorialMode = self:GetState("tutorialMode")
end
function TMAdvance:Enter()
  self:WantPadEvents(true)
  local currentMessage = tutorialUtil.GetCurrentMessage()
  currentMessage:Activate()
end
function TMAdvance:Exit()
  local currentMessage = tutorialUtil.GetCurrentMessage()
  currentMessage:Deactivate()
  self:WantPadEvents(false)
end
function TutorialMode:OnSaveCheckpoint(tab)
end
function TutorialMode:OnRestoreCheckpoint(tab)
end
