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

--Global vals.
local select, GetTime, UnitBuff = select, GetTime, UnitBuff

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

--- Provides the index for the "Incanter's Flow" aura.
-- @return The index to use with UnitBuff().
-- @see UnitBuff().
--
local function getAuraIndex()
  -- 40 is the maximum amount of possible auras.
  for i = 0, 40 do
    if UnitBuff("player", i) == IFT_AURA_NAME then
      -- Return the index.
      return i
    end
  end
end

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

eventFrame:RegisterEvent("PLAYER_REGEN_DISABLED")
eventFrame:SetScript("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()
  iftAuraIndex = iftAuraIndex or getAuraIndex()

  local spellName, _, stacks = UnitBuff("player", iftAuraIndex or 0)
  local timestamp = GetTime()
  local elapsed = timestamp - iftTimestamp

  if not iftInCombat then
    iftHasCycleState = nil
    iftCycleStart = 0
    iftPrevStack = iftStack
  end
  
  if spellName == IFT_AURA_NAME and stacks then
    iftStackLimit = iftStackLimit or (select(17, UnitBuff("player", iftAuraIndex)) / 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 IFT_AURA_NAME, 1, stacks, iftStackLimit, (iftProgress / iftStackLimit)
  elseif not stacks or spellName ~= IFT_AURA_NAME then
    iftProgress = iftStackLimit
    iftStack = 0
    iftPrevStack = 0
    iftAuraIndex = nil
  end

  return IFT_AURA_NAME, 0
end

rawset(_G, "UnitIncantersFlow", unitIncantersFlow)
