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

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

    if _type.Saved.IsCombined and not _type.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(_type, index)
    local x = ((index - 1) % _type.BarDepth) * base.Saved.ButtonXY
    local y = (math.floor((index - 1) / _type.BarDepth)) * base.Saved.ButtonXY

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

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

    _type.IsEmpty = true

    for _, _value in ipairs(_type.OrderedCollection) do
        local hideButton = true
        if _type.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(base, _type, frame, _value.Id, base.Saved)
            end

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

                local left, top = base.GetButtonPosition(_type, index)
                base.Buttons[_value.Id]:SetBindingText(base.Saved.ShowBinding, _value.Id)
                base.Buttons[_value.Id]:Setup(base)
                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
            _type.IsEmpty = false
        elseif not _type.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 = (_type.IsEmpty or not _type.Saved.LabelShow) and not base.Global.EnableSettings or not _type.Saved.Enabled
    if _type.Frame then
        _type.Frame:SetHidden(isHidden)
    end

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

function base.UpdateButtonsState(_type, forceId, isAttemptingActivation)
    for _, _value in ipairs(_type.OrderedCollection) do
        local button = base.Buttons[_value.Id]

        if button ~= nil then
            button:UpdateState(forceId, isAttemptingActivation)
        end
    end
end

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

function base.GetCooldownText(countDown, duration)
    local cooldown = ""

    if type(duration) == "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.type.Cooldown.StartTime == nil and IsCollectibleUsable(button.cId)

    if not isCollectibleUsable and button.cId then
        local startTime = button.type.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.type.Name .. tostring(button.type.EventTS), EVENT_COLLECTIBLE_USE_RESULT)
            button.type.EventTS = GetTimeStamp()
            EVENT_MANAGER:RegisterForEvent(base.Addon.Abbreviation .. button.type.Name .. tostring(button.type.EventTS), EVENT_COLLECTIBLE_USE_RESULT, function(_, result, isAttemptingActivation)
                local countDown = button.type.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.type, button.cId, isAttemptingActivation)
                end

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

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

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

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