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

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

-- Local vals
local iftInChargeCycle, iftHasCycleState, iftPrevStack, iftStackLimit, iftInCombat
local iftStack = 0
local iftTimestamp = GetTime()
local iftCycleStart = iftTimestamp
local iftProgress = 5

-- Combat watcher.
local eventFrame = CreateFrame("Frame")
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)

-- Event handler.
local unitIncantersFlow = function()
    local stacks = select(4, UnitBuff("player", "Incanter's Flow"))
    local timestamp = GetTime()
    local elapsed = timestamp - iftTimestamp

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

    if stacks then
        iftStackLimit = iftStackLimit or (select(18, UnitBuff("player", "Incanter's Flow")) / 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 "Incanter's Flow", 1, stacks, iftStackLimit, (iftProgress / iftStackLimit)
    elseif not stacks then
        iftProgress = iftStackLimit
        iftStack = 0
        iftPrevStack = 0
    end

    return "Incanter's Flow", 0
end

rawset(_G, "UnitIncantersFlow", unitIncantersFlow)
