-- ApiVault Unified Developer Search runtime helpers. Generated for ApiVault v0.3.0.
-- This file only combines already-generated metadata indexes. It does not read source files at runtime.
local addonName, ApiVault = ...

ApiVault.GlobalSearch = ApiVault.GlobalSearch or {}
local Search = ApiVault.GlobalSearch

Search.metadata = {
	version = "0.5.5",
	interface = 120007,
	policy = "metadata-only; no runtime file reads; no full Blizzard source display; no protected/secure execution",
	source_archive = "Interface.zip",
	source_sha256 = "e04620731330f6c61c16f735ecba4ff550f7ad1baaf9912b6f8715a965ff0055",
	target_package = "ApiVault-v0.5.2.zip",
}

local function lower(value)
	return string.lower(tostring(value or ""))
end

local function contains(haystack, needle)
	haystack = lower(haystack)
	needle = lower(needle)
	return needle == "" or string.find(haystack, needle, 1, true) ~= nil
end

local function addResult(results, result, limit)
	if not result then
		return true
	end
	table.insert(results, result)
	return #results < limit
end

local function categoryAllowed(category, filter)
	filter = filter or "All"
	if filter == "All" then
		return true
	end
	if filter == category then
		return true
	end
	if category == "API" and (filter == "Function" or filter == "Event" or filter == "Table") then
		return true
	end
	return false
end

local function normalizeAPIKind(kind)
	if kind == "Function" or kind == "Event" or kind == "Table" then
		return kind
	end
	return "API"
end

function Search:GetStats()
	local layers = 0
	local counts = {}

	if ApiVault.Index and ApiVault.APIData and ApiVault.APIData.metadata then
		layers = layers + 1
		counts.apiFunctions = ApiVault.APIData.metadata.functions or 0
		counts.apiEvents = ApiVault.APIData.metadata.events or 0
		counts.apiTables = ApiVault.APIData.metadata.tables or 0
	end
	if ApiVault.SourceUsage and ApiVault.SourceUsage.GetStats then
		layers = layers + 1
		counts.sourceUsageAPIs, counts.sourceUsageEvents, counts.sourceUsageModules = ApiVault.SourceUsage:GetStats()
	end
	if ApiVault.InterfaceResources and ApiVault.InterfaceResources.GetStats then
		layers = layers + 1
		counts.resourceFiles, counts.resourceFolders, counts.resourceModules = ApiVault.InterfaceResources:GetStats()
	end
	if ApiVault.XMLCatalog and ApiVault.XMLCatalog.GetStats then
		layers = layers + 1
		counts.xmlTemplates, counts.xmlFiles, counts.xmlVirtual, counts.xmlSecure = ApiVault.XMLCatalog:GetStats()
	end
	if ApiVault.ModuleCatalog and ApiVault.ModuleCatalog.GetStats then
		layers = layers + 1
		counts.moduleTOCs, counts.moduleEntries, counts.moduleFileRefs = ApiVault.ModuleCatalog:GetStats()
	end
	if ApiVault.SourceExamples and ApiVault.SourceExamples.GetStats then
		layers = layers + 1
		counts.sourceExamples, counts.apiExamples, counts.eventExamples = ApiVault.SourceExamples:GetStats()
	end
	if ApiVault.SecurePatterns and ApiVault.SecurePatterns.GetStats then
		layers = layers + 1
		counts.securePatterns, counts.protectedPatterns, counts.secureSensitive, counts.combatSensitive, counts.metadataOnly = ApiVault.SecurePatterns:GetStats()
	end

	if ApiVault.Symbols and ApiVault.Symbols.GetStats then
		layers = layers + 1
		counts.symbols, counts.documentedSymbols, counts.mixinSymbols, counts.xmlScriptSymbols, counts.slashSymbols = ApiVault.Symbols:GetStats()
	end
	if ApiVault.GlobalInspector and ApiVault.GlobalInspector.GetStats then
		layers = layers + 1
		counts.runtimeGlobalsCached, counts.runtimeGlobalsScanned, counts.runtimeGlobalsLast = ApiVault.GlobalInspector:GetStats()
	end

	if ApiVault.Catalogs and ApiVault.Catalogs.GetStats then
		layers = layers + 1
		counts.catalogs, counts.constants, counts.slashCatalog, counts.bindings, counts.settings = ApiVault.Catalogs:GetStats()
	end
	if ApiVault.Widgets and ApiVault.Widgets.GetStats then
		layers = layers + 1
		counts.widgets, counts.widgetMethods, counts.widgetScripts, counts.createFrameRefs, counts.setScriptRefs = ApiVault.Widgets:GetStats()
	end

	return layers, counts
end

function Search:Search(query, filter, limit)
	query = tostring(query or "")
	filter = filter or "All"
	limit = limit or 350

	local results = {}
	local perLayerLimit = 80

	if categoryAllowed("API", filter) and ApiVault.Index and ApiVault.Index.Search then
		local apiFilter = "All"
		if filter == "Function" or filter == "Event" or filter == "Table" then
			apiFilter = filter
		end
		local apiResults = ApiVault.Index:Search(query, apiFilter, perLayerLimit) or {}
		for _, entry in ipairs(apiResults) do
			if addResult(results, {
				category = "API",
				kind = normalizeAPIKind(entry.kind),
				display = entry.display,
				module = entry.system or "",
				riskClass = entry.risk or "",
				data = entry,
			}, limit) == false then
				return results
			end
		end
	end

	if categoryAllowed("Resource", filter) and ApiVault.InterfaceResources and ApiVault.InterfaceResources.Search then
		local resourceResults = ApiVault.InterfaceResources:Search(query, "All", perLayerLimit) or {}
		for _, entry in ipairs(resourceResults) do
			if addResult(results, {
				category = "Resource",
				kind = entry.kind or "Resource",
				display = entry.display or "?",
				module = (entry.data and entry.data.mod) or entry.name or "",
				riskClass = "metadata",
				data = entry,
			}, limit) == false then
				return results
			end
		end
	end

	if categoryAllowed("XML", filter) and ApiVault.XMLCatalog and ApiVault.XMLCatalog.Search then
		local xmlResults = ApiVault.XMLCatalog:Search(query, "All", perLayerLimit) or {}
		for _, entry in ipairs(xmlResults) do
			if addResult(results, {
				category = "XML",
				kind = "XMLTemplate",
				display = entry.display or "?",
				module = (entry.data and entry.data.mod) or "",
				riskClass = (entry.data and entry.data.sec == 1) and "secure-sensitive" or "metadata",
				data = entry,
			}, limit) == false then
				return results
			end
		end
	end

	if categoryAllowed("Module", filter) and ApiVault.ModuleCatalog and ApiVault.ModuleCatalog.Search then
		local moduleResults = ApiVault.ModuleCatalog:Search(query, "All", perLayerLimit) or {}
		for _, entry in ipairs(moduleResults) do
			if addResult(results, {
				category = "Module",
				kind = "TOCModule",
				display = entry.display or "?",
				module = (entry.data and entry.data.moduleName) or "",
				riskClass = (entry.data and (entry.data.secure == "1" or entry.data.useSecureEnvironment == "1")) and "metadata-only" or "metadata",
				data = entry,
			}, limit) == false then
				return results
			end
		end
	end

	if categoryAllowed("Example", filter) and ApiVault.SourceExamples and ApiVault.SourceExamples.Search then
		local exampleResults = ApiVault.SourceExamples:Search(query, "All", perLayerLimit) or {}
		for _, entry in ipairs(exampleResults) do
			if addResult(results, {
				category = "Example",
				kind = "SourceExample",
				display = entry.display or "?",
				module = (entry.data and entry.data.module) or "",
				riskClass = (entry.data and entry.data.riskClass) or "metadata",
				data = entry,
			}, limit) == false then
				return results
			end
		end
	end

	if categoryAllowed("Secure", filter) and ApiVault.SecurePatterns and ApiVault.SecurePatterns.Search then
		local secureResults = ApiVault.SecurePatterns:Search(query, "All", perLayerLimit) or {}
		for _, entry in ipairs(secureResults) do
			if addResult(results, {
				category = "Secure",
				kind = "SecurePattern",
				display = entry.display or "?",
				module = (entry.data and entry.data.module) or "",
				riskClass = (entry.data and entry.data.riskClass) or "secure-sensitive",
				data = entry,
			}, limit) == false then
				return results
			end
		end
	end

	if categoryAllowed("Symbol", filter) and ApiVault.Symbols and ApiVault.Symbols.Search then
		local symbolResults = ApiVault.Symbols:Search(query, "All", perLayerLimit) or {}
		for _, entry in ipairs(symbolResults) do
			if addResult(results, {
				category = "Symbol",
				kind = (entry.data and entry.data.symbolType) or "Symbol",
				display = entry.display or "?",
				module = (entry.data and entry.data.module) or "",
				riskClass = (entry.data and entry.data.callablePolicy) or "inspect-only",
				data = entry,
			}, limit) == false then
				return results
			end
		end
	end

	if categoryAllowed("Catalog", filter) and ApiVault.Catalogs and ApiVault.Catalogs.Search then
		local catalogResults = ApiVault.Catalogs:Search(query, "All", perLayerLimit) or {}
		for _, entry in ipairs(catalogResults) do
			if addResult(results, {
				category = "Catalog",
				kind = (entry.data and entry.data.catalogType) or "Catalog",
				display = entry.display or "?",
				module = (entry.data and entry.data.module) or "",
				riskClass = (entry.data and entry.data.riskClass) or "metadata",
				data = entry,
			}, limit) == false then
				return results
			end
		end
	end

	if categoryAllowed("Widget", filter) and ApiVault.Widgets and ApiVault.Widgets.Search then
		local widgetResults = ApiVault.Widgets:Search(query, "All", perLayerLimit) or {}
		for _, entry in ipairs(widgetResults) do
			if addResult(results, {
				category = "Widget",
				kind = (entry.data and entry.data.widgetType) or "Widget",
				display = entry.display or "?",
				module = (entry.data and entry.data.module) or "",
				riskClass = (entry.data and entry.data.riskClass) or "metadata",
				data = entry,
			}, limit) == false then
				return results
			end
		end
	end

	return results
end

function Search:DescribeResult(result)
	if not result then
		return "No result selected."
	end
	local lines = {}
	table.insert(lines, "Unified search result")
	table.insert(lines, "category: " .. tostring(result.category or "?"))
	table.insert(lines, "kind: " .. tostring(result.kind or "?"))
	table.insert(lines, "display: " .. tostring(result.display or "?"))
	table.insert(lines, "module: " .. tostring(result.module or ""))
	table.insert(lines, "riskClass: " .. tostring(result.riskClass or ""))

	if result.category == "API" then
		local entry = result.data
		local systemInfo = nil
		local objectInfo = nil
		if ApiVault.Index and ApiVault.Index.GetObject then
			systemInfo, objectInfo = ApiVault.Index:GetObject(entry)
		end
		table.insert(lines, "")
		table.insert(lines, "API documentation")
		table.insert(lines, "source doc: " .. tostring(systemInfo and systemInfo.file or "?"))
		table.insert(lines, "execution policy: " .. tostring(entry and entry.risk or "?") .. " (" .. tostring(entry and entry.riskReason or "?") .. ")")

		if entry and entry.kind == "Function" then
			local args = objectInfo and objectInfo.args or {}
			local rets = objectInfo and objectInfo.rets or {}
			table.insert(lines, "arguments: " .. tostring(#args))
			table.insert(lines, "returns: " .. tostring(#rets))
			if ApiVault.SourceUsage and ApiVault.SourceUsage.GetAPIUsage then
				local usage = ApiVault.SourceUsage:GetAPIUsage(entry.display)
				table.insert(lines, "sourceUsageRefs: " .. tostring(usage and usage.c or 0))
			end
			if ApiVault.SourceExamples and ApiVault.SourceExamples.GetForOwner then
				local examples = ApiVault.SourceExamples:GetForOwner(entry.display, "Function", 3)
				table.insert(lines, "sourceExamples: " .. tostring(#examples))
			end
			if ApiVault.SecurePatterns and ApiVault.SecurePatterns.GetForAPI then
				local secure = ApiVault.SecurePatterns:GetForAPI(entry.display, 3)
				table.insert(lines, "securePatterns: " .. tostring(#secure))
				if ApiVault.SecurePatterns.IsBlockedAPI and ApiVault.SecurePatterns:IsBlockedAPI(entry.display) then
					table.insert(lines, "autoRunPolicy: blocked by Secure Pattern Reference Index")
				end
			end
		elseif entry and entry.kind == "Event" then
			local payload = objectInfo and objectInfo.payload or {}
			table.insert(lines, "payload fields: " .. tostring(#payload))
			if ApiVault.SourceUsage and ApiVault.SourceUsage.GetEventUsage then
				local usage = ApiVault.SourceUsage:GetEventUsage(entry.display)
				table.insert(lines, "eventRegistrationRefs: " .. tostring(usage and usage.c or 0))
				if usage and usage.u then
					table.insert(lines, "registerUnitEventRefs: " .. tostring(usage.u))
				end
			end
			if ApiVault.SourceExamples and ApiVault.SourceExamples.GetForOwner then
				local examples = ApiVault.SourceExamples:GetForOwner(entry.display, "Event", 3)
				table.insert(lines, "sourceExamples: " .. tostring(#examples))
			end
		elseif entry and entry.kind == "Table" then
			table.insert(lines, "fields: " .. tostring(objectInfo and #(objectInfo.fields or {}) or 0))
			table.insert(lines, "values: " .. tostring(objectInfo and #(objectInfo.values or {}) or 0))
		end
		if ApiVault.DetailLinks and ApiVault.DetailLinks.AppendAPIDetail then
			local crossLinks = ApiVault.DetailLinks:AppendAPIDetail("", entry, systemInfo, objectInfo, 5)
			if crossLinks and crossLinks ~= "" then
				table.insert(lines, "")
				table.insert(lines, crossLinks)
			end
		end
	elseif result.category == "Resource" then
		if ApiVault.InterfaceResources and ApiVault.InterfaceResources.DescribeEntry then
			table.insert(lines, "")
			local text = ApiVault.InterfaceResources:DescribeEntry(result.data)
			if ApiVault.ResourceLinks and ApiVault.ResourceLinks.AppendResourceDetail then
				text = ApiVault.ResourceLinks:AppendResourceDetail(text, result.data, 5)
			end
			table.insert(lines, text)
		end
	elseif result.category == "XML" then
		if ApiVault.XMLCatalog and ApiVault.XMLCatalog.DescribeTemplate then
			table.insert(lines, "")
			local text = ApiVault.XMLCatalog:DescribeTemplate(result.data)
			if ApiVault.ResourceLinks and ApiVault.ResourceLinks.AppendXMLDetail then
				text = ApiVault.ResourceLinks:AppendXMLDetail(text, result.data, 5)
			end
			table.insert(lines, text)
		end
	elseif result.category == "Module" then
		if ApiVault.ModuleCatalog and ApiVault.ModuleCatalog.DescribeModule then
			table.insert(lines, "")
			local text = ApiVault.ModuleCatalog:DescribeModule(result.data)
			if ApiVault.ResourceLinks and ApiVault.ResourceLinks.AppendModuleDetail then
				text = ApiVault.ResourceLinks:AppendModuleDetail(text, result.data, 5)
			end
			table.insert(lines, text)
		end
	elseif result.category == "Example" then
		if ApiVault.SourceExamples and ApiVault.SourceExamples.DescribeExample then
			table.insert(lines, "")
			table.insert(lines, ApiVault.SourceExamples:DescribeExample(result.data))
		end
	elseif result.category == "Secure" then
		if ApiVault.SecurePatterns and ApiVault.SecurePatterns.DescribePattern then
			table.insert(lines, "")
			table.insert(lines, ApiVault.SecurePatterns:DescribePattern(result.data))
		end
	elseif result.category == "Catalog" then
		if ApiVault.Catalogs and ApiVault.Catalogs.Describe then
			table.insert(lines, "")
			table.insert(lines, ApiVault.Catalogs:Describe(result.data))
		end
	elseif result.category == "Widget" then
		if ApiVault.Widgets and ApiVault.Widgets.Describe then
			table.insert(lines, "")
			table.insert(lines, ApiVault.Widgets:Describe(result.data))
		end
	elseif result.category == "Symbol" then
		if ApiVault.Symbols and ApiVault.Symbols.DescribeSymbol then
			table.insert(lines, "")
			table.insert(lines, ApiVault.Symbols:DescribeSymbol(result.data))
		end
	end

	table.insert(lines, "")
	table.insert(lines, "Note: this search result is generated metadata. It does not prove runtime behavior unless the referenced API documentation explicitly states it and it is verified in-game.")
	return table.concat(lines, "\n")
end
