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

-------------------------------------------------------------------------------------------------
-- FUNCTIONS --
-------------------------------------------------------------------------------------------------
function base:Activate(button)
	base:Debug("Activate", button)

	if base:IsCollectibleUsable(button) then
		if button and base.Saved.Button.IsActiveActivationEnabled then
			local category = base.Categories[button.categoryId]
			local formatCategoryEvent = string.format(texts.FormatAbbreviation .. "%%s", category.Name)
			local activeEventName = string.format(formatCategoryEvent, tostring(category.EventTS))
			EVENT_MANAGER:UnregisterForEvent(activeEventName, EVENT_COLLECTIBLE_USE_RESULT)
			category.EventTS = GetTimeStamp()
			EVENT_MANAGER:RegisterForEvent(activeEventName, EVENT_COLLECTIBLE_USE_RESULT, function(_, result, isAttemptingActivation)
				local countDown = 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(category, button.cId, isAttemptingActivation)
				end

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

				EVENT_MANAGER:UnregisterForEvent(activeEventName, EVENT_COLLECTIBLE_USE_RESULT)

				if success then
					local countDownEvent = string.format(formatCategoryEvent, countDown.Event)
					EVENT_MANAGER:UnregisterForUpdate(countDownEvent)
					EVENT_MANAGER:RegisterForUpdate(countDownEvent, countDown.Tick, function()
						local remaining, duration = GetCollectibleCooldownAndDuration(countDown.CollectibleId)
						local cooldown = base:GetCooldownText(countDown, duration)

						base:UpdateButtonsCooldown(category, remaining, duration, cooldown)

						if duration == 0 then
							countDown.StartTime = nil
							local isActive = successActivate or IsCollectibleActive(button.cId)
							base:UpdateButtonsState(category, button.cId, isActive)
							EVENT_MANAGER:UnregisterForUpdate(countDownEvent)
						end
					end)
				end
			end)
		end

		button:UpdateUsable()
		button:OnClicked()
	end
end

function base:SetFrameAndCombineSize(category)
	base:Debug("SetFrameAndCombineSize", category)
	local width, height = base:GetBarWidthHeight(category)
	base:SetFrameSizeIfExists(category.Frames.Frame, width, height)

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

function base:GetFrame(name, virtual)
	base:Debug("GetFrame", name, virtual)

	local frame = GetControl(name)

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

	base:Debug("GetFrame:return", frame)

	return frame
end

function base:GetButtonPosition(category, index)
	category.Bar.Depth, category.Bar.Width = base:GetMaxBarSize(category, "Depth", index), base:GetMaxBarSize(category, "Width", index)

	base:Debug("GetButtonPosition", category, index, category.Bar.Depth, base.Saved.Button.Size)

	local left = ((index - 1) % category.Bar.Depth) * base.Saved.Button.Size
	local top = (zo_floor((index - 1) / category.Bar.Depth)) * base.Saved.Button.Size

	base:Debug("GetButtonPosition", category.Name, index, left, top)

	if not category.Saved.Bar.Horizontal then
		return top, left
	else
		return left, top
	end
end

function base:SetupButtons(category)
	base:Debug("SetupButtons", category, category.Name, category.Bar.Depth, category.Bar.Width)

	local index = 1
	local autoSelectAll = category.Saved.AutoSelectAll
	local selected = category.Saved.Selected
	local frame = category.Frames.Frame
	local maxIndex = (category.Bar.Depth or 0) * (category.Bar.Width or 0)

	category.IsEmpty = true

	for _, _value in ipairs(category.CollectionOrdered) do
		local hideButton = true

		if category.Saved.Enabled and (autoSelectAll or selected[_value.Id]) and IsCollectibleUnlocked(_value.Id) and IsCollectibleValidForPlayer(_value.Id) then
			if category.Buttons[_value.Id] == nil then
				category.Buttons[_value.Id] = CBs_Button:New(category.Id, frame, _value.Id)
				base.AllButtons[_value.Id] = category.Buttons[_value.Id]
			end

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

				category.Buttons[_value.Id]:SetBindingText(base.Saved.Bindings.Show, _value.Id)
				category.Buttons[_value.Id]:Setup()
				category.Buttons[_value.Id]:UpdateAnchor(frame, base:GetButtonPosition(category, index))
				category.Buttons[_value.Id]:UpdatePlaySounds(base.Saved.Button.IsAudioEnabled)
				index = index + 1
			end

			category.IsEmpty = false
		end

		if category.Buttons[_value.Id] ~= nil then
			category.Buttons[_value.Id]:SetHidden(hideButton)

			if not hideButton then
				category.Buttons[_value.Id]:SetSize(base.Saved.Button.Size)
				category.Buttons[_value.Id]:UpdateState(nil, nil, base.Saved.Button.IsActiveActivationEnabled)
			end
		end
	end

	local isHidden = (category.IsEmpty or not category.Saved.Label.Show) and not base.Global.EnableSettings or not category.Saved.Enabled

	if category.Frames.Frame then
		category.Frames.Frame:SetHidden(isHidden)
	end

	if category.Frames.Label then
		category.Frames.Label:SetHidden(isHidden)
	end
end

function base:UpdateButtonsState(category, forceId, isAttemptingActivation)
	base:Debug("UpdateButtonsState", category, forceId, isAttemptingActivation)

	for _, button in pairs(category.Buttons) do
		if button ~= nil then
			button:UpdateState(forceId, isAttemptingActivation, base.Saved.Button.IsActiveActivationEnabled)
		end
	end
end

function base:UpdateButtonsCooldown(category, remaining, duration, cooldown)
	base:Debug("UpdateButtonsCooldown", category, remaining, duration, cooldown)

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

function base:GetCooldownText(countDown, duration)
	base:Debug("GetCooldownText", countDown, duration)

	local cooldown = ""

	if type(duration) == "number" and countDown.StartTime ~= nil then
		local startTime = countDown.StartTime or 0
		local secondsRemaining = zo_max(startTime + duration - GetFrameTimeMilliseconds(), 0) / 1000
		cooldown = ZO_FormatTimeAsDecimalWhenBelowThreshold(secondsRemaining, 60)
	end

	return cooldown
end

function base:IsCollectibleUsable(button)
	base:Debug("IsCollectibleUsable", button)

	local category = base.Categories[button.categoryId]
	local isCollectibleUsable = button ~= nil and category.Cooldown.StartTime == nil and IsCollectibleUsable(button.cId)

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

	return isCollectibleUsable
end