local _, ns = ...
local SlickUI = ns.SlickUI
local Theme = SlickUI.Theme

local TrinketButtons = {
	Buttons = {},
	PendingRefresh = false,
	LastLocked = nil,
	Elapsed = 0,
}
SlickUI.TrinketButtons = TrinketButtons

local TrinketSlots = { 13, 14 }

local function IsAccessible(value)
	if canaccessvalue and not canaccessvalue(value) then return false end
	if issecretvalue and issecretvalue(value) then return false end
	return value ~= nil
end

function TrinketButtons:HasOnUse(slot)
	local itemID = GetInventoryItemID("player", slot)
	if not itemID or not C_Item or type(C_Item.GetItemSpell) ~= "function" then return false end
	local spellName, spellID = C_Item.GetItemSpell(itemID)
	return IsAccessible(spellName) and IsAccessible(spellID)
		and type(spellName) == "string" and spellName ~= "" and type(spellID) == "number"
end

function TrinketButtons:UpdateCooldown(button)
	local start, duration = GetInventoryItemCooldown("player", button.SlickSlot)
	if not IsAccessible(start) or not IsAccessible(duration) then return end
	pcall(button.Cooldown.SetCooldown, button.Cooldown, start, duration)
end

function TrinketButtons:Refresh()
	local editing = SlickUI.DB and SlickUI.DB.locked == false
	if InCombatLockdown() then
		self.PendingRefresh = true
		for _, button in ipairs(self.Buttons) do self:UpdateCooldown(button) end
		return
	end

	self.PendingRefresh = false
	for _, button in ipairs(self.Buttons) do
		local slot = button.SlickSlot
		local hasOnUse = self:HasOnUse(slot)
		local texture = GetInventoryItemTexture("player", slot)
		button.Icon:SetTexture(texture or 134400)
		button.Icon:SetDesaturated(not hasOnUse)
		button.SlickHasOnUse = hasOnUse
		button:SetShown(hasOnUse or editing)
		button.EditLabel:SetShown(editing and not hasOnUse)
		self:UpdateCooldown(button)
	end
	self.LastLocked = SlickUI.DB.locked
end

function TrinketButtons:CreateButton(slot, index)
	local button = CreateFrame("Button", "SlickUI_TrinketButton" .. index, UIParent,
		"BackdropTemplate,SecureActionButtonTemplate")
	button:SetSize(42, 42)
	button:SetFrameStrata("MEDIUM")
	button:RegisterForClicks("AnyUp", "AnyDown")
	button:SetAttribute("type", "item")
	button:SetAttribute("item", tostring(slot))
	button:SetAttribute("useOnKeyDown", false)
	button.SlickSlot = slot
	Theme:CreatePanel(button, 0.92, true)

	local icon = button:CreateTexture(nil, "ARTWORK")
	icon:SetPoint("TOPLEFT", 3, -3)
	icon:SetPoint("BOTTOMRIGHT", -3, 3)
	icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
	button.Icon = icon

	local cooldown = CreateFrame("Cooldown", nil, button, "CooldownFrameTemplate")
	cooldown:SetAllPoints(icon)
	cooldown:SetDrawEdge(false)
	cooldown:SetHideCountdownNumbers(false)
	button.Cooldown = cooldown

	local editLabel = Theme:CreateText(button, 10, "OVERLAY")
	editLabel:SetPoint("CENTER")
	editLabel:SetText("TRINKET " .. index)
	editLabel:SetTextColor(unpack(Theme.Colors.goldText))
	button.EditLabel = editLabel

	button:SetScript("OnEnter", function(self)
		if not GetInventoryItemID("player", self.SlickSlot) then return end
		GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
		GameTooltip:SetInventoryItem("player", self.SlickSlot)
		GameTooltip:Show()
	end)
	button:SetScript("OnLeave", GameTooltip_Hide)

	SlickUI.UnitFrames["trinketButton" .. index] = button
	SlickUI.Movers:Register(button, "trinketButton" .. index, "Trinket " .. index)
	self.Buttons[index] = button
	return button
end

function TrinketButtons:Initialize()
	for index, slot in ipairs(TrinketSlots) do self:CreateButton(slot, index) end
	self.EventFrame = CreateFrame("Frame")
	for _, event in ipairs({
		"PLAYER_ENTERING_WORLD", "PLAYER_EQUIPMENT_CHANGED", "GET_ITEM_INFO_RECEIVED",
		"BAG_UPDATE_COOLDOWN", "SPELL_UPDATE_COOLDOWN", "PLAYER_REGEN_ENABLED",
	}) do
		self.EventFrame:RegisterEvent(event)
	end
	self.EventFrame:SetScript("OnEvent", function(_, event, slot)
		if event ~= "PLAYER_EQUIPMENT_CHANGED" or slot == 13 or slot == 14 then
			C_Timer.After(0, function() TrinketButtons:Refresh() end)
		end
	end)
	self.EventFrame:SetScript("OnUpdate", function(_, elapsed)
		TrinketButtons.Elapsed = TrinketButtons.Elapsed + elapsed
		if TrinketButtons.Elapsed < 0.25 then return end
		TrinketButtons.Elapsed = 0
		if TrinketButtons.LastLocked ~= SlickUI.DB.locked or TrinketButtons.PendingRefresh then
			TrinketButtons:Refresh()
		else
			for _, button in ipairs(TrinketButtons.Buttons) do
				if button:IsShown() then TrinketButtons:UpdateCooldown(button) end
			end
		end
	end)
	self:Refresh()
end

SlickUI:RegisterModule("TrinketButtons", TrinketButtons)
