local classlib = require("core.class")
local tablex = require("core.tablex")
local consts = require("ui.consts")
local hooks = require("ui.hooks")
local lamsConsts = require("ui.lamsConsts")
local sliderHoldFill = require("ui.sliderHoldFill")
local uiCalls = require("ui.uicalls")
local util = require("ui.util")
local Audio = game.Audio
local UI = game.UI
local MessageRequest = classlib.Class("MessageRequest")
MessageRequest.s_timerCount = 0
local HandleEvent = function(messageRequest, events, handler, callTable)
  if messageRequest:get_active() then
    if handler ~= nil then
      handler(messageRequest)
    elseif callTable ~= nil then
      for _, call in ipairs(callTable) do
        local callName = call.CallName
        local argTable = call.ArgTable
        if argTable == nil then
          argTable = {}
        end
        uiCalls[callName](unpack(argTable))
      end
    end
    if tablex.Contains(events, "EVT_Advance_Release") then
      Audio.PlaySound("SND_UX_Menu_Tick_Confirm")
    elseif tablex.Contains(events, "EVT_Back_Release") then
      Audio.PlaySound("SND_UX_Menu_Tick_Back")
    end
    if messageRequest._AdvanceToNextMessage ~= nil then
      messageRequest._AdvanceToNextMessage()
    end
  end
end
function MessageRequest:init(state, args)
  self._state = state
  self._active = false
  self._goMessageRequest = args.MessageObject
  self._goMessageRequestChild = nil
  self._goBlur = nil
  self._goTextObjects = nil
  self._useUIAccessibilityScaling = args.UseUIAccessibilityScaling or false
  self._maxUIAccessibilityScaling = args.MaxUIAccessibilityScaling or 1.15
  self._bodyMessage = util.GetValueWithDefault(args.BodyMessage, "")
  self._headerMessage = util.GetValueWithDefault(args.HeaderMessage, "")
  self._textStyle = args.TextStyle
  self._time = util.GetValueWithDefault(args.Time, 5)
  self._messageDelay = util.GetValueWithDefault(args.MessageDelay, 0)
  self._exitDelay = util.GetValueWithDefault(args.ExitDelay, 0)
  self._advanceType = util.GetValueWithDefault(args.AdvanceType, uiCalls.msgParam.ADVANCE_TIMER)
  self._messageType = util.GetValueWithDefault(args.MessageType, uiCalls.msgParam.MESSAGE_STANDARD)
  self._unpauseWhenComplete = args.UnpauseWhenComplete
  self._itemCardArgs = args.ItemCardArgs
  self._terminateCallback = args.TerminateCallback
  self._clearedOutCallback = args.ClearedOutCallback
  self._formattedArgs = args.FormattedArgs
  self._enterSound = args.EnterSound
  self._exitSound = args.ExitSound
  self._continueSound = args.ContinueSound
  self._playSound = self._enterSound ~= nil or self._exitSound ~= nil or self._continueSound ~= nil or args.PlaySound
  self._animSpeed = args.AnimSpeed or 5
  self._fadeInTime = args.FadeInTime or 0.2
  self._fadeOutTime = args.FadeOutTime or 0.2
  self._fadeInDelay = args.FadeInDelay or 0
  self._exitAnimSpeed = args.ExitAnimSpeed or self._animSpeed
  self._animateFadeGOs = args.AnimateFadeGOs or false
  self._optionsOverride = args.OptionsOverride
  self._completionHook = args.CompletionHook or nil
  self._completionHookCalled = false
  self._sliderHoldFill = nil
  self._hookTokens = {}
  self._eventHandlers = {}
  self._footerButtonInfo = util.GetValueWithDefault(args.FooterButtonInfo, {
    {
      Text = "[AdvanceButton] " .. util.GetLAMSMsg(lamsConsts.Close),
      EventHandlers = {
        {
          Events = {
            "EVT_Advance_Release"
          },
          Handler = nil
        }
      }
    }
  })
  self._continueFooterButtonInfo = util.GetValueWithDefault(args.ContinueFooterButtonInfo, self._footerButtonInfo)
  self._AdvanceToNextMessage = args.AdvanceToNextMessage
  self._OnExitTransitionBegin = args.OnExitTransitionBegin
  self:SetGameObject(self._goMessageRequest)
  local isTypeThatPausesTheGame = self._advanceType == uiCalls.msgParam.ADVANCE_PRESS or self._advanceType == uiCalls.msgParam.ADVANCE_HOLD
  if self._unpauseWhenComplete == nil then
    self._unpauseWhenComplete = not isTypeThatPausesTheGame
  end
  if self._playSound == nil then
    self._playSound = isTypeThatPausesTheGame
  end
  if self._advanceType == uiCalls.msgParam.ADVANCE_HOLD then
    self:SetSliderHoldFill(nil)
  end
end
function MessageRequest:Activate(useContinueFooterInfo)
  if not self._active then
    local footerText = ""
    local footerInfoToUse = self._footerButtonInfo
    if useContinueFooterInfo then
      footerInfoToUse = self._continueFooterButtonInfo
    end
    for index, info in ipairs(footerInfoToUse) do
      if info.Text ~= nil then
        footerText = footerText .. info.Text
        if index < #footerInfoToUse then
          footerText = footerText .. consts.Footer_Spacer
        end
      end
      local eventHandlers = info.EventHandlers
      if eventHandlers ~= nil then
        for _, item in ipairs(eventHandlers) do
          util.InstallEventHooks(hooks, self, item.Events, function(messageRequest)
            HandleEvent(messageRequest, item.Events, item.Handler, item.UICalls)
          end)
          tablex.FastInsert(self._eventHandlers, item, #self._eventHandlers + 1)
        end
      end
    end
    local thButtonPrompts = self:GetTextHandle("ButtonPrompts")
    self:SetText(thButtonPrompts, footerText)
    UI.SetTextIsClickable(thButtonPrompts)
    UI.SetTextIsDialog(thButtonPrompts)
    UI.SetInUI(true)
    self._active = true
  end
end
function MessageRequest:Deactivate()
  if self._active then
    self._active = false
    UI.SetInUI(false)
    for _, item in ipairs(self._eventHandlers) do
      util.UninstallEventHooks(hooks, self, item.Events)
    end
    local thButtonPrompts = self:GetTextHandle("ButtonPrompts")
    self:SetText(thButtonPrompts, "")
    tablex.Clear(self._hookTokens)
  end
end
function MessageRequest:Show()
  if self._goMessageRequest ~= nil then
    self._goMessageRequest:Show()
    self._goMessageRequestChild:Show()
    if self._goBlur ~= nil then
      self._goBlur:Show()
    end
    if self._goTextObjects ~= nil then
      self._goTextObjects:Show()
    end
  end
end
function MessageRequest:Hide()
  if self._goMessageRequest ~= nil then
    self._goMessageRequest:Hide()
    self._goMessageRequestChild:Hide()
    if self._goBlur ~= nil then
      self._goBlur:Hide()
    end
    if self._goTextObjects ~= nil then
      self._goTextObjects:Hide()
    end
  end
end
function MessageRequest:OnExitTransitionBegin()
  if self._OnExitTransitionBegin ~= nil then
    self._OnExitTransitionBegin(self)
  end
end
function MessageRequest:PlaySound(soundName)
  assert(not util.IsStringNilOrEmpty(soundName), "MessageRequest attempted to play a nil sound!")
  if self._playSound then
    Audio.PlaySound(soundName)
  end
end
function MessageRequest:SetGameObject(goMessageRequest)
  self._goMessageRequest = goMessageRequest
  if self._goMessageRequest == nil then
    self._goMessageRequestChild = nil
    self._goBlur = nil
    self._goTextObjects = nil
  else
    self._goMessageRequestChild = self._goMessageRequest:FindSingleGOByName("message")
    assert(self._goMessageRequestChild ~= nil, "MessageRequest:SetGameObject called with instance that does not have a message root object!")
    self._goBlur = self._goMessageRequest:FindSingleGOByName("blur")
    self._goTextObjects = self._goMessageRequestChild:FindSingleGOByName("TextObjects")
    if self._useUIAccessibilityScaling then
      self:UpdateAccessibilityScaling()
    end
  end
end
function MessageRequest:UpdateAccessibilityScaling()
  if UI.GetAccessibilityScaling == nil then
    return
  end
  if self._goMessageRequest ~= nil then
    self._goMessageRequest:SetScale(UI.GetAccessibilityScaling(1, self._maxUIAccessibilityScaling))
  end
end
function MessageRequest:SetSliderHoldFill(onCompleteFunc)
  local goHoldToFillSlider = self._goMessageRequestChild:FindSingleGOByName("HoldToFillSlider")
  if goHoldToFillSlider ~= nil then
    self._sliderHoldFill = sliderHoldFill.SliderHoldFill.New(self._state, {
      Name = "MessagePromptAdvancer",
      SliderObject = goHoldToFillSlider,
      StopWhenFull = true,
      IncAnimRate = 0.75,
      DecAnimRate = 2,
      OnComplete = onCompleteFunc
    })
    self._sliderHoldFill:SetValue(0)
    self._sliderHoldFill:Setup()
    self._sliderHoldFill:SetText("")
  end
end
function MessageRequest:SetHeaderMessage(message)
  self._headerMessage = message
end
function MessageRequest:SetBodyMessage(message)
  self._bodyMessage = message
end
function MessageRequest:SetExitDelay(exitDelay)
  self._exitDelay = exitDelay
end
function MessageRequest:SetFooterButtonInfo(footerButtonInfo)
  self._footerButtonInfo = footerButtonInfo
end
function MessageRequest:SetText(thHandle, message, useStyle)
  if thHandle ~= nil then
    local text
    if type(message) ~= "number" then
      if self._formattedArgs then
        message = string.format(message, unpack(self._formattedArgs))
      end
      text = tostring(message)
    else
      local lamsSuccessfullyAcquired
      if self._formattedArgs then
        text, lamsSuccessfullyAcquired = util.FormatLAMSString(message, unpack(self._formattedArgs))
      else
        text, lamsSuccessfullyAcquired = util.GetLAMSMsg(message)
      end
      assert(lamsSuccessfullyAcquired, "Invalid LAMS ID entered:" .. tostring(message))
    end
    if text ~= nil then
      if self._textStyle ~= nil and useStyle then
        text = "<" .. self._textStyle .. ">" .. text
      end
      UI.SetText(thHandle, text)
    end
  end
end
function MessageRequest:AnimateIn(fadeGOs, playBaseAnim)
  if playBaseAnim == true then
    local startTime = 0
    local animSpeed = self._animSpeed
    if 0 >= self._animSpeed then
      startTime = 1
      animSpeed = 0
    end
    UI.Anim(self._goMessageRequestChild, consts.AS_Forward, "", animSpeed, startTime)
    if self._goBlur ~= nil then
      UI.Anim(self._goBlur, consts.AS_Forward, "", animSpeed, startTime)
    end
  end
  local fadeInTargetAlpha = 1
  for _, object in pairs(fadeGOs) do
    if self._animateFadeGOs then
      UI.Anim(object, consts.AS_Forward, "", self._animSpeed)
    else
      UI.AlphaFade(object, 0, 0)
      if 0 < self._fadeInDelay then
        MessageRequest.s_timerCount = MessageRequest.s_timerCount + 1
        local timerName = "MessageRequestFadeInHelper_" .. tostring(MessageRequest.s_timerCount)
        self._state:StartTimer(timerName, self._fadeInDelay, function()
          UI.AlphaFade(object, fadeInTargetAlpha, self._fadeInTime)
          self._state:DeleteTimer(timerName)
        end)
      else
        UI.AlphaFade(object, fadeInTargetAlpha, self._fadeInTime)
      end
    end
  end
end
function MessageRequest:AnimateOut(fadeGOs, playBaseAnim)
  if playBaseAnim == true then
    local startTime = 0
    local animSpeed = self._exitAnimSpeed
    local animPlaybackStyle = consts.AS_Reverse
    if 0 >= self._exitAnimSpeed then
      startTime = 1
      animSpeed = 0
    end
    if self._itemCardArgs ~= nil and self._itemCardArgs.SendAnimEndEvent == true then
      animPlaybackStyle = bit32.bor(consts.AS_Reverse, consts.AS_EndEvent)
    end
    UI.Anim(self._goMessageRequestChild, animPlaybackStyle, "", animSpeed, startTime)
    if self._goBlur ~= nil then
      UI.Anim(self._goBlur, consts.AS_Reverse, "", animSpeed, startTime)
    end
  end
  local fadeOutTargetAlpha = 0
  for _, object in pairs(fadeGOs) do
    if self._animateFadeGOs then
      UI.Anim(object, consts.AS_Reverse, "", self._exitAnimSpeed)
    else
      UI.AlphaFade(object, fadeOutTargetAlpha, self._fadeOutTime)
    end
  end
end
function MessageRequest:CallCompletionHook()
  if not self._completionHookCalled then
    self._completionHookCalled = true
    if self._completionHook ~= nil then
      assert(self._completionHook.HookName ~= nil, string.format("Hook to level %s was nil", self._completionHook.LevelName))
      local callHookOnMe = game.FindLevel(self._completionHook.LevelName)
      assert(callHookOnMe ~= nil, string.format("Could not find level %s", self._completionHook.LevelName))
      if self._completionHook.ObjectName ~= nil then
        callHookOnMe = callHookOnMe:FindSingleGameObject(self._completionHook.ObjectName)
        assert(callHookOnMe ~= nil, string.format("Could not find object %s in level %s", self._completionHook.ObjectName, self._completionHook.LevelName))
      end
      local hookArgs = self._completionHook.Args
      if hookArgs == nil then
        hookArgs = {}
      end
      callHookOnMe:CallScript(self._completionHook.HookName, unpack(hookArgs))
    end
  end
end
function MessageRequest:PlayEnterSound()
  if self._enterSound ~= nil then
    self:PlaySound(self._enterSound)
  end
end
function MessageRequest:PlayExitSound()
  if self._exitSound ~= nil then
    self:PlaySound(self._exitSound)
  end
end
function MessageRequest:PlayContinueSound()
  if self._continueSound ~= nil then
    self:PlaySound(self._continueSound)
  end
end
function MessageRequest:GetTextHandle(textObjectName)
  assert(self._goTextObjects ~= nil, "MessageRequest attempted to get text handle but no TextObjects object exists!")
  assert(textObjectName ~= nil, "MessageRequest attempted to get text handle without a text object name!")
  return util.GetTextHandle(self._goTextObjects, textObjectName)
end
function MessageRequest:get_active()
  return self._active
end
function MessageRequest:get_goMessageRequest()
  return self._goMessageRequest
end
function MessageRequest:get_goMessageRequestChild()
  return self._goMessageRequestChild
end
function MessageRequest:get_goBlur()
  return self._goBlur
end
function MessageRequest:get_goTextObjects()
  return self._goTextObjects
end
function MessageRequest:get_sliderHoldFill()
  return self._sliderHoldFill
end
function MessageRequest:get_headerMessage()
  return self._headerMessage
end
function MessageRequest:get_bodyMessage()
  return self._bodyMessage
end
function MessageRequest:get_time()
  return self._time
end
function MessageRequest:get_messageDelay()
  return self._messageDelay
end
function MessageRequest:get_exitDelay()
  return self._exitDelay
end
function MessageRequest:get_advanceType()
  return self._advanceType
end
function MessageRequest:get_messageType()
  return self._messageType
end
function MessageRequest:get_itemCardArgs()
  return self._itemCardArgs
end
function MessageRequest:get_unpauseWhenComplete()
  return self._unpauseWhenComplete
end
function MessageRequest:get_textStyle()
  return self._textStyle
end
function MessageRequest:get_terminateCallback()
  return self._terminateCallback
end
function MessageRequest:get_clearedOutCallback()
  return self._clearedOutCallback
end
function MessageRequest:get_formattedArgs()
  return self._formattedArgs
end
function MessageRequest:get_optionsOverride()
  return self._optionsOverride
end
return {MessageRequest = MessageRequest}
