local Range = SUI:NewModule("ActionBars.Range");

function Range:OnEnable()
    local db = SUI.db.profile.actionbar

    if (db.buttons.range) then
        local Module = CreateFrame('Frame')
        local _G = _G
        local next = _G.next
        local pairs = _G.pairs
        local unpack = _G.unpack

        local HasAction = _G.HasAction
        local IsActionInRange = _G.IsActionInRange
        local IsUsableAction = _G.IsUsableAction

        local UPDATE_DELAY = .2
        local buttonColors, buttonsToUpdate = {}, {}
        local updater = CreateFrame("Frame")

        local colors = {
            ["normal"] = { 1, 1, 1 },
            ["oor"] = { .8, .1, .1 },
            ["oom"] = { .5, .5, 1 },
            ["unusable"] = { .3, .3, .3 }
        }

        function Module:OnUpdateRange(elapsed)
            self.elapsed = (self.elapsed or UPDATE_DELAY) - elapsed
            if self.elapsed <= 0 then
                self.elapsed = UPDATE_DELAY

                if not Module:UpdateButtons() then
                    self:Hide()
                end
            end
        end

        updater:SetScript("OnUpdate", Module.OnUpdateRange)

        function Module:UpdateButtons()
            if next(buttonsToUpdate) then
                for button in pairs(buttonsToUpdate) do
                    self.UpdateButtonUsable(button)
                end
                return true
            end

            return false
        end

        function Module:UpdateButtonStatus()
            local action = self.action

            if action and self:IsVisible() and HasAction(action) then
                buttonsToUpdate[self] = true
            else
                buttonsToUpdate[self] = nil
            end

            if next(buttonsToUpdate) then
                updater:Show()
            end
        end

        function Module:UpdateButtonUsable(force)
            if force then
                buttonColors[self] = nil
            end

            local action = self.action
            local isUsable, notEnoughMana = IsUsableAction(action)

            if isUsable then
                local inRange = IsActionInRange(action)
                if inRange == false then
                    Module.SetButtonColor(self, "oor")
                else
                    Module.SetButtonColor(self, "normal")
                end
            elseif notEnoughMana then
                Module.SetButtonColor(self, "oom")
            else
                Module.SetButtonColor(self, "unusable")
            end
        end

        function Module:SetButtonColor(colorIndex)
            if buttonColors[self] == colorIndex then
                return
            end
            buttonColors[self] = colorIndex

            local r, g, b = unpack(colors[colorIndex])
            self.icon:SetVertexColor(r, g, b)
        end

        function Module:Register()
            self:HookScript("OnShow", Module.UpdateButtonStatus)
            self:HookScript("OnHide", Module.UpdateButtonStatus)
            self:SetScript("OnUpdate", nil)
            Module.UpdateButtonStatus(self)
        end

        local function button_UpdateUsable(button)
            Module.UpdateButtonUsable(button, true)
        end

        function Module:RegisterButtonRange(button)
            if button.UpdateAction then
                Module.Register(button)
                hooksecurefunc(button, "UpdateAction", Module.UpdateButtonStatus)
                hooksecurefunc("ActionButton_UpdateUsable", function()
                    button_UpdateUsable(button)
                end)
                --hooksecurefunc(button, "UpdateUsable", button_UpdateUsable)
            end
        end

        for i = 1, NUM_ACTIONBAR_BUTTONS do
            Module:RegisterButtonRange(_G["ActionButton" .. i])
            Module:RegisterButtonRange(_G["MultiBarBottomLeftButton" .. i])
            Module:RegisterButtonRange(_G["MultiBarBottomRightButton" .. i])
            Module:RegisterButtonRange(_G["MultiBarRightButton" .. i])
            Module:RegisterButtonRange(_G["MultiBarLeftButton" .. i])
        end
    end
end
