-- ApiVault Developer Debug Dashboard data/formatting helpers. Added in v1.1.5.
-- Data-only dashboard over ApiVault.DeveloperAPI records. Does not execute external addon code.
local addonName, ApiVault = ...

ApiVault.DeveloperDebugDashboard = ApiVault.DeveloperDebugDashboard or {}
local Dashboard = ApiVault.DeveloperDebugDashboard

local function safeString(value)
	if value == nil then return "" end
	return tostring(value)
end

local function asNumber(value)
	return tonumber(value) or 0
end

local function sortNames(names)
	table.sort(names, function(a, b) return tostring(a) < tostring(b) end)
	return names
end

local function countMap(map)
	local count = 0
	for _ in pairs(map or {}) do count = count + 1 end
	return count
end

local function countList(list)
	return #(list or {})
end

local function getDevAPI()
	return ApiVault and ApiVault.DeveloperAPI
end

function Dashboard:GetAddonNames()
	local dev = getDevAPI()
	if dev and dev.GetAddonNames then
		return dev:GetAddonNames()
	end
	local names = {}
	for name in pairs((dev and dev.addons) or {}) do table.insert(names, name) end
	return sortNames(names)
end

function Dashboard:GetRecord(addon)
	local dev = getDevAPI()
	if not dev then return nil end
	if dev.GetAddonRecord then return dev:GetAddonRecord(addon) end
	return dev.addons and dev.addons[addon]
end

function Dashboard:FindFirstAddon()
	local names = self:GetAddonNames()
	return names and names[1]
end

function Dashboard:ResolveAddon(addon)
	addon = safeString(addon)
	if addon ~= "" and self:GetRecord(addon) then return addon end
	return self:FindFirstAddon()
end

function Dashboard:SummarizeRecord(name, record)
	record = record or {}
	return {
		name = name,
		version = record.metadata and record.metadata.version or "",
		interface = record.metadata and record.metadata.interface or "",
		registered = record.registered,
		firstSeen = record.firstSeen,
		lastActivity = record.lastActivity,
		logs = countList(record.logs),
		errors = countList(record.errors),
		apiTraces = countList(record.apiTraces),
		eventTraces = countList(record.eventTraces),
		secureRisks = countList(record.secureRisks),
		savedVariables = countList(record.savedVariables),
		checkpoints = countList(record.checkpoints),
		sessions = countMap(record.sessions),
	}
end

function Dashboard:BuildRegisteredOverview()
	local names = self:GetAddonNames()
	local lines = {}
	table.insert(lines, "ApiVault Developer Debug Dashboard")
	table.insert(lines, "Registered addons: " .. tostring(#names))
	table.insert(lines, "Policy: external addon input is data-only; ApiVault does not execute addon-provided code.")
	table.insert(lines, "")
	for _, name in ipairs(names) do
		local record = self:GetRecord(name)
		local s = self:SummarizeRecord(name, record)
		table.insert(lines, string.format("%s | version=%s | errors=%d | APIs=%d | events=%d | secure=%d | SV=%d | sessions=%d", safeString(s.name), safeString(s.version), s.errors, s.apiTraces, s.eventTraces, s.secureRisks, s.savedVariables, s.sessions))
		if s.lastActivity then table.insert(lines, "  lastActivity: " .. safeString(s.lastActivity)) end
	end
	if #names == 0 then
		table.insert(lines, "No addons have registered through ApiVault:GetPublicAPI(...) yet.")
		table.insert(lines, "Use ApiVaultDebugTest or an external addon bridge to submit data.")
	end
	return table.concat(lines, "\n")
end

local function makeTimelineItem(kind, item)
	item = item or {}
	local label = ""
	if kind == "errors" then label = item.message or item.error or "error"
	elseif kind == "apiTraces" then label = item.apiName or "api"
	elseif kind == "eventTraces" then label = item.eventName or "event"
	elseif kind == "secureRisks" then label = item.pattern or item.name or "secure-risk"
	elseif kind == "savedVariables" then label = item.name or item.variable or item.savedVariable or "SavedVariables"
	elseif kind == "checkpoints" then label = item.label or item.message or "checkpoint"
	else label = item.message or item.label or kind end
	return { kind = kind, time = asNumber(item.time), wallTime = item.wallTime, label = label, item = item }
end

function Dashboard:BuildUnifiedTimeline(record, limit)
	limit = limit or 120
	local entries = {}
	local buckets = { "logs", "errors", "apiTraces", "eventTraces", "secureRisks", "savedVariables", "checkpoints" }
	for _, bucket in ipairs(buckets) do
		for _, item in ipairs(record and record[bucket] or {}) do
			table.insert(entries, makeTimelineItem(bucket, item))
		end
	end
	table.sort(entries, function(a, b)
		if a.time == b.time then return tostring(a.kind) < tostring(b.kind) end
		return a.time > b.time
	end)
	while #entries > limit do table.remove(entries) end
	return entries
end

function Dashboard:FormatTimeline(addon, kind, limit)
	addon = self:ResolveAddon(addon)
	local record = addon and self:GetRecord(addon)
	if not record then return "No developer debug data available." end
	local lines = {}
	table.insert(lines, "Timeline: " .. safeString(kind or "all"))
	table.insert(lines, "addon: " .. safeString(addon))
	table.insert(lines, "")
	local entries = {}
	if kind == "all" or kind == nil then
		entries = self:BuildUnifiedTimeline(record, limit or 120)
	else
		for _, item in ipairs(record[kind] or {}) do table.insert(entries, makeTimelineItem(kind, item)) end
	end
	for index, entry in ipairs(entries) do
		if index > (limit or 120) then break end
		table.insert(lines, string.format("%03d. [%s] %s | time=%s | wall=%s", index, safeString(entry.kind), safeString(entry.label), safeString(entry.time), safeString(entry.wallTime)))
		local item = entry.item or {}
		if item.context and item.context ~= "" then table.insert(lines, "     context: " .. safeString(item.context)) end
		if item.file and item.file ~= "" then table.insert(lines, "     file: " .. safeString(item.file) .. ":" .. safeString(item.line or "")) end
		if item.registration then table.insert(lines, "     registration: " .. safeString(item.registration)) end
		if item.autoRunPolicy then table.insert(lines, "     autoRunPolicy: " .. safeString(item.autoRunPolicy)) end
		if item.advice and item.advice.category then table.insert(lines, "     category: " .. safeString(item.advice.category)) end
		if item.bugAdvisorId then table.insert(lines, "     bugAdvisorId: " .. safeString(item.bugAdvisorId)) end
	end
	if #entries == 0 then table.insert(lines, "No entries in this timeline.") end
	return table.concat(lines, "\n")
end

function Dashboard:FormatSavedVariables(addon)
	addon = self:ResolveAddon(addon)
	local record = addon and self:GetRecord(addon)
	if not record then return "No developer debug data available." end
	local lines = {}
	table.insert(lines, "SavedVariables status")
	table.insert(lines, "addon: " .. safeString(addon))
	table.insert(lines, "reports: " .. tostring(countList(record.savedVariables)))
	table.insert(lines, "")
	for index, item in ipairs(record.savedVariables or {}) do
		table.insert(lines, string.format("%03d. %s | initialized=%s | schemaVersion=%s", index, safeString(item.name or item.variable or "SavedVariables"), safeString(item.initialized), safeString(item.schemaVersion)))
		if item.scope then table.insert(lines, "     scope: " .. safeString(item.scope)) end
		if item.notes then table.insert(lines, "     notes: " .. safeString(item.notes)) end
	end
	if countList(record.savedVariables) == 0 then table.insert(lines, "No SavedVariables reports submitted through the public API.") end
	return table.concat(lines, "\n")
end

function Dashboard:FormatSessions(addon)
	addon = self:ResolveAddon(addon)
	local record = addon and self:GetRecord(addon)
	if not record then return "No developer debug data available." end
	local lines = {}
	table.insert(lines, "Debug sessions")
	table.insert(lines, "addon: " .. safeString(addon))
	table.insert(lines, "")
	local names = {}
	for name in pairs(record.sessions or {}) do table.insert(names, name) end
	sortNames(names)
	for _, name in ipairs(names) do
		local session = record.sessions[name] or {}
		table.insert(lines, "session: " .. safeString(name))
		table.insert(lines, "  started: " .. safeString(session.started))
		table.insert(lines, "  ended: " .. safeString(session.ended))
		if session.status then table.insert(lines, "  status: " .. safeString(session.status)) end
		if session.notes then table.insert(lines, "  notes: " .. safeString(session.notes)) end
	end
	if #names == 0 then table.insert(lines, "No sessions submitted through the public API.") end
	return table.concat(lines, "\n")
end

function Dashboard:FormatCompleteReport(addon)
	addon = self:ResolveAddon(addon)
	local record = addon and self:GetRecord(addon)
	if not record then return "No developer debug data available." end
	local dev = getDevAPI()
	local lines = {}
	table.insert(lines, "ApiVault Complete Developer Debug Report")
	table.insert(lines, "addon: " .. safeString(addon))
	table.insert(lines, "")
	if dev and dev.FormatAddonReport then table.insert(lines, dev:FormatAddonReport(addon)) end
	table.insert(lines, "")
	table.insert(lines, self:FormatTimeline(addon, "all", 80))
	table.insert(lines, "")
	table.insert(lines, self:FormatSavedVariables(addon))
	table.insert(lines, "")
	table.insert(lines, self:FormatSessions(addon))
	table.insert(lines, "")
	table.insert(lines, "Policy: this report is generated from data submitted through ApiVault's public debug API. It is advisory and does not prove source correctness.")
	return table.concat(lines, "\n")
end

function Dashboard:FormatDashboard(addon, view)
	view = view or "overview"
	if view == "overview" then return self:BuildRegisteredOverview() end
	if view == "errors" then return self:FormatTimeline(addon, "errors", 120) end
	if view == "apis" then return self:FormatTimeline(addon, "apiTraces", 120) end
	if view == "events" then return self:FormatTimeline(addon, "eventTraces", 120) end
	if view == "secure" then return self:FormatTimeline(addon, "secureRisks", 120) end
	if view == "savedvariables" then return self:FormatSavedVariables(addon) end
	if view == "sessions" then return self:FormatSessions(addon) end
	if view == "export" then return self:FormatCompleteReport(addon) end
	return self:FormatTimeline(addon, "all", 120)
end

function Dashboard:GetStats()
	local names = self:GetAddonNames()
	local totalEvents = 0
	for _, name in ipairs(names) do
		local r = self:GetRecord(name) or {}
		totalEvents = totalEvents + countList(r.logs) + countList(r.errors) + countList(r.apiTraces) + countList(r.eventTraces) + countList(r.secureRisks) + countList(r.savedVariables) + countList(r.checkpoints)
	end
	return #names, totalEvents
end
