local classlib = require("core.class")
local tablex = require("core.tablex")
local consts = require("ui.consts")
local hooks = require("ui.hooks")
local log = require("ui.log")
local messageRowTimer = require("ui.messageRowTimer")
local pickupUtil = require("ui.pickupUtil")
local resourceConsts = require("ui.resourceConsts")
local util = require("ui.util")
local Pickup = game.Pickup
local Player = game.Player
local UI = game.UI
local LogTimer = classlib.Class("LogTimer", log.Log)
local GetTimeValueFromArg = function(arg)
  return arg / 100
end
local TimerStartHandler = function(logTimer)
  local pickupName = Pickup.GetName(UI.GetEventArgInt(1))
  local originalTimeOut = GetTimeValueFromArg(UI.GetEventArgInt(2))
  local goSender = UI.GetEventSenderGameObject()
  if logTimer:ShouldHandlePickup(goSender, pickupName) == true then
    for _, message in ipairs(logTimer._messageArray) do
      for _, row in ipairs(message:get_rows()) do
        if row:get_resourceName() == pickupName then
          return
        end
      end
    end
    local newMessageArgs = {
      Header = nil,
      Sound = "SND_UX_Notification_Loot_Collect",
      BodyDisplayTime = 1,
      RowArray = {}
    }
    local newRow = logTimer:CreateMessageRowTimer({
      ResourceName = pickupName,
      ResourceType = resourceConsts.RESOURCE_FLAG_PICKUP,
      Amount = originalTimeOut,
      IsMaxed = false
    })
    tablex.FastInsert(newMessageArgs.RowArray, newRow, 1)
    logTimer:AddMessage(newMessageArgs)
  end
end
local TimerChangeHandler = function(logTimer)
  local pickupName = Pickup.GetName(UI.GetEventArgInt(1))
  local currentTime = GetTimeValueFromArg(UI.GetEventArgInt(2))
  local originalTimeOut = GetTimeValueFromArg(UI.GetEventArgInt(3))
  local goSender = UI.GetEventSenderGameObject()
  if logTimer:ShouldHandlePickup(goSender, pickupName) == true then
    logTimer:UpdateTimerChange(pickupName, currentTime, originalTimeOut)
  end
end
local TimerEndHandler = function(logTimer)
  local pickupName = Pickup.GetName(UI.GetEventArgInt(1))
  local goSender = UI.GetEventSenderGameObject()
  if logTimer:ShouldHandlePickup(goSender, pickupName) == true and logTimer:GetMessageCount() > 0 then
    local displayedMessage = logTimer:GetMessage(1)
    local displayedMessageOldRowCount = displayedMessage:GetRowCount()
    logTimer:RemoveMessageRowByPickup(pickupName)
    logTimer:UpdateRows(displayedMessage, displayedMessageOldRowCount)
  end
end
local ItemLostHandler = function(logTimer)
  local pickupName = Pickup.GetName(UI.GetEventArgInt(1))
  local goSender = UI.GetEventSenderGameObject()
  if logTimer:ShouldHandlePickup(goSender, pickupName) == true and logTimer:GetMessageCount() > 0 then
    local displayedMessage = logTimer:GetMessage(1)
    local displayedMessageOldRowCount = displayedMessage:GetRowCount()
    logTimer:RemoveMessageRowByPickup(pickupName)
    logTimer:UpdateRows(displayedMessage, displayedMessageOldRowCount)
  end
end
function LogTimer:init(state, args)
  self._state = state
  self._active = false
  self._goSender = args.SenderGameObject
  self._includeTags = util.GetValueWithDefault(args.IncludeTags, {})
end
function LogTimer:Activate()
  if not self._active then
    util.InstallEventHooks(hooks, self, {
      "EVT_Item_Timer_Start"
    }, TimerStartHandler)
    util.InstallEventHooks(hooks, self, {
      "EVT_Item_Timer_Change"
    }, TimerChangeHandler)
    util.InstallEventHooks(hooks, self, {
      "EVT_Item_Timer_End"
    }, TimerEndHandler)
    util.InstallEventHooks(hooks, self, {
      "EVT_Item_Lost"
    }, ItemLostHandler)
    self._active = true
  end
end
function LogTimer:FadeOut()
  UI.AlphaFade(self._goLog, 0, 0.3)
end
function LogTimer:FadeIn()
  UI.AlphaFade(self._goLog, 1, 0.3)
end
function LogTimer:Deactivate()
  if self._active then
    self._active = false
    util.UninstallEventHooks(hooks, self, {
      "EVT_Item_Timer_Start"
    })
    util.UninstallEventHooks(hooks, self, {
      "EVT_Item_Timer_Change"
    })
    util.UninstallEventHooks(hooks, self, {
      "EVT_Item_Timer_End"
    })
    util.UninstallEventHooks(hooks, self, {
      "EVT_Item_Lost"
    })
    tablex.Clear(self._hookTokens)
  end
end
function LogTimer:ShouldHandlePickup(goSender, pickupName)
  local shouldHandle = false
  local senderIsValid = self._goSender == nil or self._goSender ~= nil and self._goSender == goSender
  if senderIsValid then
    for _, tag in ipairs(self._includeTags) do
      if pickupUtil.HasTag(pickupName, tag) == true then
        shouldHandle = true
        break
      end
    end
  end
  return shouldHandle
end
function LogTimer:CreateMessageRowTimer(args)
  return messageRowTimer.MessageRowTimer.New(self._state, {
    ResourceName = args.ResourceName,
    ResourceType = args.ResourceType,
    Count = args.Amount,
    IsMaxed = args.IsMaxed,
    AnimInRate = self._animInRate,
    AnimOutRate = self._animOutRate,
    RowTextFadeTime = self._fadeOutTime,
    Material = self._material,
    Layer = self._layer,
    Attribute = self._attribute,
    TextIndexNames = self._textIndexNames
  })
end
function LogTimer:HandleNewMessage(newMessage)
  if self:GetMessageCount() == 0 then
    self:EnqueueMessage(newMessage)
    self:Start(newMessage)
  else
    local displayedMessage = self:GetMessage(1)
    local displayedMessageOldRowCount = displayedMessage:GetRowCount()
    self:MoveItemsIntoMessageArray(newMessage)
    self:UpdateRows(displayedMessage, displayedMessageOldRowCount)
  end
end
function LogTimer:MoveItemsIntoMessageArray(newMessage)
  newMessage:RemoveInvalidItems()
  for _, row in ipairs(newMessage:get_rows()) do
    for _, message in ipairs(self._messageArray) do
      if message:GetRowCount() < message:GetMaxDisplayRowCount() then
        self:TakeItem(message, row)
        message:SetDisplayRowIndex(message:GetDisplayRowIndex() - 1)
      end
    end
  end
  newMessage:RemoveInvalidItems()
  if newMessage:GetRowCount() > 0 then
    self:EnqueueMessage(newMessage)
  end
end
function LogTimer:UpdateTimerChange(pickupName, currentTime, originalTimeOut)
  for _, message in ipairs(self._messageArray) do
    for rowIndex, row in ipairs(message:get_rows()) do
      if row:get_resourceName() == pickupName then
        row:set_count(currentTime)
        row:DisplayRowCount(rowIndex)
      end
    end
  end
end
function LogTimer:RemoveMessageRowByPickup(pickupName)
  for _, message in ipairs(self._messageArray) do
    for _, row in ipairs(message:get_rows()) do
      if row:get_resourceName() == pickupName then
        row:set_count(-1)
        message:SetDisplayRowIndex(message:GetDisplayRowIndex() - 1)
      end
    end
    message:RemoveInvalidItems()
  end
  for _, message in ipairs(self._messageArray) do
    local currMaxDisplayRowCount = message:GetMaxDisplayRowCount()
    if currMaxDisplayRowCount > message:GetRowCount() then
      local nextMessage = self:GetMessage()
      if nextMessage ~= nil then
        for _, row in ipairs(nextMessage:get_rows()) do
          if currMaxDisplayRowCount > message:GetRowCount() then
            self:TakeItem(message, row)
            nextMessage:SetDisplayRowIndex(nextMessage:GetDisplayRowIndex() - 1)
          end
        end
        nextMessage:RemoveInvalidItems()
      end
    end
  end
  for messageIndex = self:GetMessageCount(), 1, -1 do
    local currMessage = self:GetMessage(messageIndex)
    if currMessage:GetRowCount() == 0 then
      self:DequeueMessage()
    end
  end
  if self:GetMessageCount() == 0 then
    self:AnimateOut()
  end
end
function LogTimer:Start(message)
  if message ~= nil then
    self._goLog:Show()
    self:ResetAllText()
    for rowIndex, row in ipairs(message:get_rows()) do
      local goRow = message:GetRowGOByIndex(rowIndex)
      row:AnimateOut(goRow, 0)
    end
    self:AnimateIn(message)
  end
end
function LogTimer:AnimateIn(message)
  self:AnimateInChildObject(self._goLog, "log", nil)
  self:AnimateInChildObject(self._goLog, "blur", nil)
  self:AnimateInChildObject(self._goLog, "glow", nil)
  self:UpdateRows(message, 0)
end
function LogTimer:AnimateOut()
  self:AnimateOutChildObject(self._goLog, "log", nil)
  self:AnimateOutChildObject(self._goLog, "blur", nil)
  self:AnimateOutChildObject(self._goLog, "glow", nil)
  self:FadeOutAll(nil)
  self._state:StartTimer(self._timerName, self._fadeOutTime, function()
    self:Finish()
  end)
end
function LogTimer:Finish()
  self:ResetAllText()
  if self:GetMessageCount() >= 1 then
    self._state:StartTimer(self._timerName, self._fadeOutTime, function()
      self:Start(self:GetMessage(1))
    end)
  else
    self._goLog:Hide()
  end
end
function LogTimer:TakeItem(message, otherRow)
  local newMessageRow = messageRowTimer.MessageRowTimer.New(self._state, {
    ResourceName = otherRow:get_resourceName(),
    Count = otherRow:get_count(),
    IsMaxed = otherRow:get_isMaxed(),
    TextIndexNames = otherRow:get_textIndexNames(),
    ResourceType = otherRow:get_resourceType()
  })
  tablex.FastInsert(message._rows, newMessageRow, #message._rows + 1)
  otherRow:set_count(-1)
end
function LogTimer:UpdateRows(message, oldDisplayIndex)
  local maxDisplayRowCount = message:GetMaxDisplayRowCount()
  for rowIndex = 1, maxDisplayRowCount do
    if rowIndex <= message:GetRowCount() then
      local row = message:GetRowByIndex(rowIndex)
      if rowIndex <= oldDisplayIndex then
        local goRow = message:GetRowGOByIndex(rowIndex)
        local bodyColor = row:GetResourceNameColor()
        local displayName = row:GetDisplayName()
        row:DisplayRowIcon(goRow)
        row:DisplayRowText(goRow, displayName, rowIndex, bodyColor, 0)
        row:DisplayRowCount(rowIndex)
      else
        row:Start(message, rowIndex)
      end
    else
      local goRow = message:GetRowGOByIndex(rowIndex)
      UI.Anim(goRow, consts.AS_Reverse, "", self._fadeOutTime, 1, 0)
      UI.AlphaFade(goRow, 0, self._fadeOutTime)
    end
  end
end
return {LogTimer = LogTimer}
