local addonName, ApiVault = ...

ApiVault.RuntimeGlobalsPanel = ApiVault.RuntimeGlobalsPanel or {}

local ROW_HEIGHT = 22
local ROW_COUNT = 22
local FILTERS = { "All", "function", "table", "string", "number", "boolean", "frame/userdata", "other" }

local function createFont(parent, template, justify)
	local font = parent:CreateFontString(nil, "OVERLAY", template or "GameFontNormal")
	font:SetJustifyH(justify or "LEFT")
	return font
end

local function setBackdrop(frame, r, g, b, a)
	if not frame.SetBackdrop then return end
	frame:SetBackdrop({
		bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
		edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
		tile = true,
		tileSize = 32,
		edgeSize = 32,
		insets = { left = 8, right = 8, top = 8, bottom = 8 },
	})
	frame:SetBackdropColor(r or 0.04, g or 0.04, b or 0.06, a or 0.96)
end

local function createBackdropFrame(name, parent)
	return CreateFrame("Frame", name, parent, BackdropTemplateMixin and "BackdropTemplate" or nil)
end

function ApiVault.RuntimeGlobalsPanel:Create()
	if self.frame then return end

	local frame = createBackdropFrame("ApiVaultRuntimeGlobalsPanelFrame", UIParent)
	self.frame = frame
	frame:SetSize(980, 640)
	frame:SetPoint("CENTER", 180, -110)
	frame:SetFrameStrata("FULLSCREEN_DIALOG")
	frame:SetMovable(true)
	frame:EnableMouse(true)
	frame:RegisterForDrag("LeftButton")
	frame:SetScript("OnDragStart", frame.StartMoving)
	frame:SetScript("OnDragStop", frame.StopMovingOrSizing)
	if frame.SetResizable then
		frame:SetResizable(true)
		if frame.SetResizeBounds then
			frame:SetResizeBounds(820, 520)
		elseif frame.SetMinResize then
			frame:SetMinResize(820, 520)
		end
	end
	setBackdrop(frame)
	if ApiVault.PrepareWindow then ApiVault:PrepareWindow(frame, "RuntimeGlobalsPanel") end
	frame:Hide()

	local close = CreateFrame("Button", nil, frame, "UIPanelCloseButton")
	close:SetPoint("TOPRIGHT", -6, -6)

	local title = createFont(frame, "GameFontHighlightLarge")
	title:SetPoint("TOPLEFT", 18, -16)
	title:SetText("ApiVault - Runtime Global Inspector")

	local sub = createFont(frame, "GameFontDisableSmall")
	self.sub = sub
	sub:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -4)
	sub:SetPoint("RIGHT", frame, "RIGHT", -28, 0)
	sub:SetText("Read-only _G snapshot. ApiVault does not call discovered functions or load modules.")

	local refresh = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
	refresh:SetSize(100, 22)
	refresh:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -44, -66)
	refresh:SetText("Refresh")
	refresh:SetScript("OnClick", function()
		if ApiVault.GlobalInspector and ApiVault.GlobalInspector.Refresh then
			ApiVault.GlobalInspector:Refresh(2000)
		end
		self:Refresh()
	end)

	local search = CreateFrame("EditBox", nil, frame, "InputBoxTemplate")
	self.search = search
	search:SetSize(320, 24)
	search:SetPoint("TOPLEFT", frame, "TOPLEFT", 18, -66)
	search:SetAutoFocus(false)
	search:SetScript("OnTextChanged", function() self:Refresh() end)

	local buttons = {}
	local last = nil
	for _, filter in ipairs(FILTERS) do
		local button = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
		button:SetSize(filter == "frame/userdata" and 112 or 78, 22)
		if last then
			button:SetPoint("LEFT", last, "RIGHT", 5, 0)
		else
			button:SetPoint("TOPLEFT", search, "BOTTOMLEFT", 0, -10)
		end
		button:SetText(filter)
		button:SetScript("OnClick", function()
			self.filter = filter
			self:Refresh()
		end)
		buttons[filter] = button
		last = button
	end

	local listFrame = createBackdropFrame(nil, frame)
	self.listFrame = listFrame
	listFrame:SetPoint("TOPLEFT", frame, "TOPLEFT", 18, -128)
	listFrame:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", 18, 28)
	listFrame:SetWidth(370)
	setBackdrop(listFrame, 0.02, 0.02, 0.03, 0.72)

	local detail = CreateFrame("EditBox", nil, frame)
	self.detail = detail
	detail:SetMultiLine(true)
	detail:SetAutoFocus(false)
	detail:SetFontObject(ChatFontNormal)
	detail:SetPoint("TOPLEFT", listFrame, "TOPRIGHT", 20, -6)
	detail:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -28, 32)
	detail:SetText("Press Refresh or select a runtime global.")
	detail:EnableMouse(true)

	self.rows = {}
	for i = 1, ROW_COUNT do
		local row = CreateFrame("Button", nil, listFrame)
		row:SetHeight(ROW_HEIGHT)
		row:SetPoint("LEFT", listFrame, "LEFT", 12, 0)
		row:SetPoint("RIGHT", listFrame, "RIGHT", -12, 0)
		if i == 1 then
			row:SetPoint("TOP", listFrame, "TOP", 0, -12)
		else
			row:SetPoint("TOP", self.rows[i - 1], "BOTTOM", 0, 0)
		end
		row.text = createFont(row, "GameFontNormalSmall")
		row.text:SetPoint("LEFT")
		row.text:SetPoint("RIGHT")
		row.text:SetText("")
		row:SetScript("OnClick", function(button)
			if ApiVault.GlobalInspector and ApiVault.GlobalInspector.Describe then
				self.detail:SetText(ApiVault.GlobalInspector:Describe(button.entry))
			end
		end)
		self.rows[i] = row
	end

	self.filter = "All"
end

function ApiVault.RuntimeGlobalsPanel:Refresh()
	if not self.frame then return end
	local query = self.search and self.search:GetText() or ""
	local filter = self.filter or "All"
	local results = {}
	if ApiVault.GlobalInspector and ApiVault.GlobalInspector.Search then
		results = ApiVault.GlobalInspector:Search(query, filter, ROW_COUNT) or {}
	end
	for i, row in ipairs(self.rows or {}) do
		local entry = results[i]
		row.entry = entry
		if entry then
			row.text:SetText(tostring(entry.display or "?"))
			row:Show()
		else
			row.text:SetText("")
			row:Hide()
		end
	end
	if self.sub and ApiVault.GlobalInspector and ApiVault.GlobalInspector.GetStats then
		local cached, scanned, last = ApiVault.GlobalInspector:GetStats()
		self.sub:SetText("Read-only _G snapshot. cached=" .. tostring(cached) .. " scanned=" .. tostring(scanned) .. " last=" .. tostring(last))
	end
end

function ApiVault.RuntimeGlobalsPanel:Toggle()
	self:Create()
	if self.frame:IsShown() then
		self.frame:Hide()
	else
		if ApiVault.RaiseWindow then ApiVault:RaiseWindow(self.frame) end
		self.frame:Show()
		if ApiVault.GlobalInspector and ApiVault.GlobalInspector.Refresh and (#(ApiVault.GlobalInspector.cache or {}) == 0) then
			ApiVault.GlobalInspector:Refresh(2000)
		end
		self:Refresh()
	end
end
