--- Provides a global function for Incanter's Flow information
--

--Global vals.
local select, GetTime, FindAuraByName = select, GetTime, AuraUtil.FindAuraByName

-- Local vals
local iftInChargeCycle, iftHasCycleState, iftPrevStack, iftStackLimit, iftInCombat, iftAuraIndex
local iftStack = 0
local iftTimestamp = GetTime()
local iftCycleStart = iftTimestamp
local iftProgress = 5
local INCANTERS_FLOW = "Incanter's Flow"

-- Combat watcher.
local eventFrame = CreateFrame("Frame", "ift_combat_watcher")

eventFrame:RegisterEvent("PLAYER_REGEN_DISABLED")
eventFrame:HookScript("OnEvent", function(self, event)
  iftInCombat = (event == "PLAYER_REGEN_DISABLED")
  self:UnregisterEvent(event)

  if event == "PLAYER_REGEN_DISABLED" then
    self:RegisterEvent("PLAYER_REGEN_ENABLED")
  elseif event == "PLAYER_REGEN_ENABLED" then
    self:RegisterEvent("PLAYER_REGEN_DISABLED")
  end
end)

--- Provides information for the Incanter's Flow buff.(Mage)
-- @return The Incanter's Flow information.
-- @see UnitBuff().
--
local function unitIncantersFlow()
  local spellName, _, stacks = FindAuraByName(INCANTERS_FLOW, "player")
  local timestamp = GetTime()
  local elapsed = timestamp - iftTimestamp

  if not iftInCombat then
    iftHasCycleState = nil
    iftCycleStart = 0
    iftPrevStack = iftStack
  end

  if spellName == INCANTERS_FLOW and stacks then
    iftStackLimit = iftStackLimit or (select(17, FindAuraByName(INCANTERS_FLOW, "player")) / stacks)
    iftHasCycleState = iftHasCycleState or ((iftPrevStack ~= iftStack) and true or nil)

    if stacks ~= iftStack or ((elapsed > 1.1) and (stacks == iftStack)) then
      iftHasCycleState = (stacks ~= iftStack) and true or iftHasCycleState
      iftPrevStack = iftStack
      iftStack = stacks
      iftTimestamp = timestamp
      elapsed = 0

      if (iftStack == iftPrevStack) and iftHasCycleState then
        iftCycleStart = timestamp
        iftInChargeCycle = (iftStack == 1) and true or nil
      elseif ((timestamp - iftCycleStart) > iftStackLimit) and iftHasCycleState then
        iftCycleStart = timestamp
        iftInChargeCycle = (iftStack > iftPrevStack) and true or nil
        iftCycleStart = iftInChargeCycle and (iftCycleStart - stacks + 1) or (iftCycleStart - (iftStackLimit - stacks))
      end
    end

    if iftHasCycleState and ((timestamp - iftCycleStart) <= iftStackLimit) then
      iftProgress = iftInChargeCycle and (timestamp - iftCycleStart) or (iftStackLimit - (timestamp - iftCycleStart))
    end

    return INCANTERS_FLOW, 1, stacks, iftStackLimit, (iftProgress / iftStackLimit)
  elseif not stacks or spellName ~= INCANTERS_FLOW then
    iftProgress = iftStackLimit
    iftStack = 0
    iftPrevStack = 0
    iftAuraIndex = nil
  end

  return INCANTERS_FLOW, 0
end

rawset(_G, "UnitIncantersFlow", unitIncantersFlow)
