--ui/event_panel.lua, side panel listing per-event trigger counts (frontend).
--a child panel anchored to the right edge of the main /fps panel, holding a Details Framework
--scrollbox. it shows live counts from core/event_counter.lua, refreshed on a throttle while
--visible (cost-free when hidden, since the driver's OnUpdate only fires then). it appears only
--when the event-counter checkbox is on (and the main panel is open, as it is a child of it).

local _ = nil
local addonName, private = ...

local detailsFramework = DetailsFramework

private.UI = private.UI or {}

--constants
local SIDE_WIDTH = 240
local SIDE_GAP = 4
local SCROLL_MARGIN = 10
local SCROLL_TOP = 34
local LINE_HEIGHT = 18
local REFRESH_INTERVAL = 0.25

---@class FPSPP_EventPanel
local EventPanel = {}
private.UI.EventPanel = EventPanel

--reusable sorted [{event, count}] array the scrollbox reads; rebuilt in place on each refresh.
EventPanel.sortedData = {}

--rebuilds sortedData from the live counts, ordered by count descending.
local rebuildSortedData = function()
	local data = EventPanel.sortedData
	wipe(data)
	for eventName, count in pairs(private.Core.EventCounter:GetCounts()) do
		data[#data + 1] = {event = eventName, count = count}
	end

	table.sort(data, function(left, right) return left.count > right.count end)
end

--scrollbox line factory: a row with the event name on the left and its count on the right.
local createLine = function(self, index)
	local line = CreateFrame("Frame", "$parentLine" .. index, self)
	line:SetSize(self:GetWidth(), LINE_HEIGHT)
	line:SetPoint("topleft", self, "topleft", 0, -(index - 1) * LINE_HEIGHT)

	line.EventText = line:CreateFontString(nil, "overlay", "GameFontHighlightSmall")
	line.EventText:SetPoint("left", line, "left", 4, 0)
	line.EventText:SetJustifyH("left")

	line.CountText = line:CreateFontString(nil, "overlay", "GameFontHighlightSmall")
	line.CountText:SetPoint("right", line, "right", -4, 0)
	line.CountText:SetJustifyH("right")

	return line
end

--scrollbox refresh: fills each visible line from the sorted data, hiding the spare lines.
local refreshScroll = function(self, data, offset, totalLines)
	for i = 1, totalLines do
		local entry = data[i + offset]
		local line = self:GetLine(i)
		if entry then
			line.EventText:SetText(entry.event)
			line.CountText:SetText(entry.count)
			line:Show()
		else
			line:Hide()
		end
	end
end

--rebuilds the sorted data and refreshes the scrollbox.
function EventPanel:Refresh()
	rebuildSortedData()
	self.scroll:Refresh()
end

--shows the side panel when the event-counter checkbox is on, hides it otherwise. it is a child
--of the main panel, so it only actually appears while the main panel is open.
function EventPanel:UpdateVisibility()
	if private.Core.Profile:GetBool("event_counter.enabled") then
		self.panel:Show()
		self:Refresh()
	else
		self.panel:Hide()
	end
end

--builds the side panel (a non-draggable child of the main options panel, anchored to its right)
--and its scrollbox, plus a throttled driver that refreshes the list while the panel is visible.
--called once from OnInit, after the main options panel exists.
---@param mainPanel table the main /fps options panel to attach to
function EventPanel:Initialize(mainPanel)
	local height = mainPanel:GetHeight()
	local panel = detailsFramework:CreateSimplePanel(mainPanel, SIDE_WIDTH, height, private.locale["EVENTS_TITLE"], "FPSPlusPlusEventPanel", {NoCloseButton = true, NoScripts = true})
	panel:SetPoint("topleft", mainPanel, "topright", SIDE_GAP, 0)

	local scrollWidth = SIDE_WIDTH - SCROLL_MARGIN * 2
	local scrollHeight = height - SCROLL_TOP - SCROLL_MARGIN
	local lineAmount = math.floor(scrollHeight / LINE_HEIGHT)

	local scroll = detailsFramework:CreateScrollBox(panel, "$parentScroll", refreshScroll, self.sortedData, scrollWidth, scrollHeight, lineAmount, LINE_HEIGHT)
	scroll:SetPoint("topleft", panel, "topleft", SCROLL_MARGIN, -SCROLL_TOP)
	for index = 1, lineAmount do
		scroll:CreateLine(createLine)
	end
	self.scroll = scroll

	--throttled driver: refreshes the list while the panel is visible (its OnUpdate only fires
	--while shown, so this costs nothing when the panel is hidden).
	local elapsedSinceRefresh = 0
	local driver = CreateFrame("Frame", nil, panel)
	driver:SetScript("OnUpdate", function(_, elapsed)
		elapsedSinceRefresh = elapsedSinceRefresh + elapsed
		if elapsedSinceRefresh < REFRESH_INTERVAL then
			return
		end

		elapsedSinceRefresh = 0
		EventPanel:Refresh()
	end)

	self.panel = panel
	self:UpdateVisibility()
end
