--[[
Author: Jarth
Filename: CBs_Buttons.lua
]] --
-------------------------------------------------------------------------------------------------
-- VARIABLES --
-------------------------------------------------------------------------------------------------
local base = CollectionBars
local texts = base.Texts

-------------------------------------------------------------------------------------------------
-- FUNCTIONS --
-------------------------------------------------------------------------------------------------
function base.SetFrameAndCombineSize(category)
    local width, height = base.GetBarWidthHeight(category)
    base.SetFrameSizeIfExists(category.Frame, width, height)

    if category.Saved.IsCombined and not category.Saved.HideAll then base.SetFrameSizeIfExists(base.Global.Combine.Frame, width, height) end
end

function base.GetFrame(name, virtual)
    local frame = GetControl(name)

    if frame == nil then frame = base.WM:CreateControlFromVirtual(name, GuiRoot, virtual) end

    return frame
end

function base.GetButtonPosition(category, index)
    local x = ((index - 1) % category.BarDepth) * base.Saved.ButtonXY
    local y = (math.floor((index - 1) / category.BarDepth)) * base.Saved.ButtonXY

    if not category.Saved.Horizontal then
        return y, x
    else
        return x, y
    end
end

function base.SetupButtons(category)
    local index = 1
    local selected = category.Saved.Selected
    local frame = category.Frame
    local maxIndex = (category.BarDepth or 0) * (category.BarWidth or 0)

    category.IsEmpty = true

    for _, _value in ipairs(category.CollectionOrdered) do
        local hideButton = true
        if category.Saved.Enabled and selected[_value.Id] and IsCollectibleUnlocked(_value.Id) and IsCollectibleValidForPlayer(_value.Id) then
            if base.Buttons[_value.Id] == nil then base.Buttons[_value.Id] = CBs_Button:New(category, frame, _value.Id, base.Saved) end

            if not category.Saved.HideAll and (maxIndex == 0 or index <= maxIndex) then
                hideButton = false

                local left, top = base.GetButtonPosition(category, index)
                base.Buttons[_value.Id]:SetBindingText(base.Saved.ShowBinding, _value.Id)
                base.Buttons[_value.Id]:Setup()
                base.Buttons[_value.Id]:UpdateAnchor(frame, left, top)
                base.Buttons[_value.Id]:UpdatePlaySounds(base.Saved.IsAudioEnabled)
                base.Buttons[_value.Id]:UpdateState()
                index = index + 1
            end
            category.IsEmpty = false
        elseif not category.Saved.Enabled and base.Buttons[_value.Id] ~= nil then
            base.Buttons[_value.Id]:SetHidden(true)
        end

        if base.Buttons[_value.Id] ~= nil then
            base.Buttons[_value.Id].ctrl:SetHidden(hideButton)
            base.Buttons[_value.Id]:SetSize(base.Saved.ButtonXY)
            base.Buttons[_value.Id]:UpdateState()
        end
    end

    local isHidden = (category.IsEmpty or not category.Saved.LabelShow) and not base.Global.EnableSettings or not category.Saved.Enabled
    if category.Frame then category.Frame:SetHidden(isHidden) end

    if category.FrameLabel then category.FrameLabel:SetHidden(isHidden) end
end

function base.UpdateButtonsState(category, forceId, isAttemptingActivation)
    for _, _value in ipairs(category.CollectionOrdered) do
        local button = base.Buttons[_value.Id]
        if button ~= nil then button:UpdateState(forceId, isAttemptingActivation) end
    end
end

function base.UpdateButtonsCooldown(category, remaining, duration, cooldown)
    for _cId in pairs(category.Saved.Selected) do
        local button = base.Buttons[_cId]
        if button ~= nil and category.Collection[_cId] then button:UpdateCooldown(remaining, duration, cooldown) end
    end
end

function base.GetCooldownText(countDown, duration)
    local cooldown = texts.Helpers.EmptyString

    if type(duration) == texts.Helpers.Number and countDown.StartTime ~= nil then
        local startTime = countDown.StartTime or 0
        local secondsRemaining = math.max(startTime + duration - GetFrameTimeMilliseconds(), 0) / 1000
        cooldown = ZO_FormatTimeAsDecimalWhenBelowThreshold(secondsRemaining, 60)
    end

    return cooldown
end

function base.IsCollectibleUsable(button)
    local isCollectibleUsable = button ~= nil and button.category.Cooldown.StartTime == nil and IsCollectibleUsable(button.cId)

    if not isCollectibleUsable and button.cId then
        local startTime = button.category.Cooldown.StartTime or 0
        local _, duration = GetCollectibleCooldownAndDuration(button.cId)
        isCollectibleUsable = startTime + duration < GetFrameTimeMilliseconds()
    end

    return isCollectibleUsable
end

function base.Activate(button)
    if base.IsCollectibleUsable(button) then
        if button and base.Saved.IsActiveActivationEnabled then
            EVENT_MANAGER:UnregisterForEvent(base.Addon.Abbreviation .. button.category.Name .. tostring(button.category.EventTS), EVENT_COLLECTIBLE_USE_RESULT)
            button.category.EventTS = GetTimeStamp()
            EVENT_MANAGER:RegisterForEvent(base.Addon.Abbreviation .. button.category.Name .. tostring(button.category.EventTS), EVENT_COLLECTIBLE_USE_RESULT,
                                           function(_, result, isAttemptingActivation)
                local countDown = button.category.Cooldown
                local success = false

                if result == COLLECTIBLE_USAGE_BLOCK_REASON_NOT_BLOCKED and button.button then
                    success = true
                    countDown.CollectibleId = button.cId
                    base.UpdateButtonsState(button.category, button.cId, isAttemptingActivation)
                end

                local successActivate = isAttemptingActivation and success
                countDown.StartTime = GetFrameTimeMilliseconds()

                EVENT_MANAGER:UnregisterForEvent(base.Addon.Abbreviation .. button.category.Name .. tostring(button.category.EventTS), EVENT_COLLECTIBLE_USE_RESULT)

                if success then
                    EVENT_MANAGER:UnregisterForUpdate(base.Addon.Abbreviation .. button.category.Name .. countDown.Event)
                    EVENT_MANAGER:RegisterForUpdate(base.Addon.Abbreviation .. button.category.Name .. countDown.Event, countDown.Tick, function()
                        local remaining, duration = GetCollectibleCooldownAndDuration(countDown.CollectibleId)
                        local cooldown = base.GetCooldownText(countDown, duration)

                        base.UpdateButtonsCooldown(button.category, remaining, duration, cooldown)
                        if duration == 0 then
                            countDown.StartTime = nil
                            local isActive = successActivate or IsCollectibleActive(button.cId)
                            base.UpdateButtonsState(button.category, button.cId, isActive)
                            EVENT_MANAGER:UnregisterForUpdate(base.Addon.Abbreviation .. button.category.Name .. countDown.Event)
                        end
                    end)
                end
            end)
        end
        button:UpdateUsable()
        button:OnClicked()
    end
end