-- ApiVault TODO completion polish helpers. Added in v0.5.4.
-- Metadata-only UX layer for filters, relationship cards, quick-copy text, navigation and policy labels.
local addonName, ApiVault = ...

ApiVault.TodoCompletion = ApiVault.TodoCompletion or {}
local Polish = ApiVault.TodoCompletion

Polish.metadata = {
    version = "0.5.4",
    interface = 120007,
    policy = "metadata-only TODO completion polish; no runtime file reads; no full source display; no protected/secure execution",
    completedTodoGroups = 9,
}

local BASE_FILTERS = {
    "All", "API", "Function", "Event", "Table", "Resource", "XML", "Module", "Example", "Secure", "Symbol",
    "HasUsage", "HasExamples", "HasSecure", "Safe", "Review", "Protected", "Metadata", "SourceBacked", "InspectOnly",
}

local ADVANCED_FILTERS = {
    HasUsage = true,
    HasExamples = true,
    HasSecure = true,
    Safe = true,
    Review = true,
    Protected = true,
    Metadata = true,
    SourceBacked = true,
    InspectOnly = true,
}

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

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

local function dataOf(result)
    if type(result) ~= "table" then return nil end
    local data = result.data
    if type(data) == "table" and type(data.data) == "table" then
        return data.data
    end
    return data
end

local function displayOf(result)
    if type(result) ~= "table" then return "" end
    return tostring(result.display or result.name or (dataOf(result) and (dataOf(result).ownerName or dataOf(result).patternName or dataOf(result).symbolName)) or "")
end

function Polish:GetStats()
    return self.metadata.completedTodoGroups or 0, "todo completion polish filters/actions/navigation"
end

function Polish:GetFilterList()
    return BASE_FILTERS
end

function Polish:IsAdvancedFilter(filter)
    return ADVANCED_FILTERS[tostring(filter or "")] and true or false
end

function Polish:NormalizeContext(raw)
    if type(raw) ~= "table" then
        return nil
    end
    if raw.category then
        return raw
    end
    return {
        category = raw.category or raw.ownerType or raw.kind or raw.type or "Item",
        kind = raw.kind or raw.ownerType or raw.type or "Item",
        display = raw.display or raw.name or raw.ownerName or raw.patternName or raw.symbolName or raw.moduleName or raw.exampleId or "?",
        module = raw.module or raw.system or raw.mod or "",
        riskClass = raw.riskClass or raw.risk or raw.callablePolicy or "",
        data = raw,
    }
end

function Polish:SetCurrentContext(context, source)
    self.currentContext = self:NormalizeContext(context)
    self.currentSource = source or "unknown"
    if ApiVault.UserState and self.currentContext then
        ApiVault.UserState:AddRecent(self.currentContext, "TodoCompletion:" .. tostring(source or "unknown"))
    end
end

function Polish:GetCurrentContext()
    return self.currentContext
end

function Polish:GetSourceUsageCount(result)
    if type(result) ~= "table" then return 0 end
    if result.category == "API" and result.data then
        local entry = result.data
        if entry.kind == "Function" and ApiVault.SourceUsage and ApiVault.SourceUsage.GetAPIUsage then
            local usage = ApiVault.SourceUsage:GetAPIUsage(entry.display)
            return usage and (usage.c or 0) or 0
        elseif entry.kind == "Event" and ApiVault.SourceUsage and ApiVault.SourceUsage.GetEventUsage then
            local usage = ApiVault.SourceUsage:GetEventUsage(entry.display)
            return usage and (usage.c or 0) or 0
        end
    end
    local data = dataOf(result)
    return tonumber(data and (data.api or data.evt or data.event or data.apiUsageCount or data.eventUsageCount) or 0) or 0
end

function Polish:GetExampleCount(result)
    if type(result) ~= "table" then return 0 end
    if result.category == "Example" then return 1 end
    if result.category == "API" and result.data and ApiVault.SourceExamples and ApiVault.SourceExamples.GetForOwner then
        local list = ApiVault.SourceExamples:GetForOwner(result.data.display, result.data.kind, 50)
        return #(list or {})
    end
    local data = dataOf(result)
    if data and data.ownerName then return 1 end
    return 0
end

function Polish:GetSecureCount(result)
    if type(result) ~= "table" then return 0 end
    if result.category == "Secure" then return 1 end
    if result.category == "API" and result.data and result.data.kind == "Function" and ApiVault.SecurePatterns and ApiVault.SecurePatterns.GetForAPI then
        return #(ApiVault.SecurePatterns:GetForAPI(result.data.display, 50) or {})
    end
    local data = dataOf(result)
    if data then
        local path = data.sp or data.sourcePath or data.addonPath
        local template = data.name or data.n or data.template or data.linkedTemplate
        local module = data.mod or data.module or data.moduleName or data.linkedModule
        local count = 0
        if path and ApiVault.SecurePatterns and ApiVault.SecurePatterns.GetForFile then count = count + #(ApiVault.SecurePatterns:GetForFile(path, 50) or {}) end
        if template and ApiVault.SecurePatterns and ApiVault.SecurePatterns.GetForTemplate then count = count + #(ApiVault.SecurePatterns:GetForTemplate(template, 50) or {}) end
        if module and ApiVault.SecurePatterns and ApiVault.SecurePatterns.GetForModule then count = count + #(ApiVault.SecurePatterns:GetForModule(module, 50) or {}) end
        return count
    end
    return 0
end

function Polish:PassesAdvancedFilter(result, filter)
    if not self:IsAdvancedFilter(filter) then return true end
    local risk = lower(result and result.riskClass or "")
    local data = dataOf(result)
    if filter == "HasUsage" then return self:GetSourceUsageCount(result) > 0 end
    if filter == "HasExamples" then return self:GetExampleCount(result) > 0 end
    if filter == "HasSecure" then return self:GetSecureCount(result) > 0 end
    if filter == "Safe" then return risk == "safe" or risk == "documented-safe" or risk == "safe-reference-only" end
    if filter == "Review" then return contains(risk, "review") or contains(risk, "restricted") end
    if filter == "Protected" then return contains(risk, "protected") or contains(risk, "blocked") end
    if filter == "Metadata" then return contains(risk, "metadata") end
    if filter == "InspectOnly" then return contains(risk, "inspect") or (data and data.autoRunPolicy == "inspect-only") or (data and data.callablePolicy == "inspect-only") end
    if filter == "SourceBacked" then return (data and (data.sourceBacked == true or data.sourceBacked == 1 or data.sourcePath or data.sp)) and true or false end
    return true
end

function Polish:FilterResults(results, filter, limit)
    local out = {}
    limit = tonumber(limit) or 350
    for _, result in ipairs(results or {}) do
        if self:PassesAdvancedFilter(result, filter) then
            out[#out + 1] = self:DecorateResult(result)
            if #out >= limit then break end
        end
    end
    return out
end

function Polish:DecorateResult(result)
    if type(result) ~= "table" then return result end
    result.sourceUsageCount = self:GetSourceUsageCount(result)
    result.exampleCount = self:GetExampleCount(result)
    result.secureCount = self:GetSecureCount(result)
    result.todoBadges = self:GetBadges(result)
    result.relationshipCount = (result.sourceUsageCount or 0) + (result.exampleCount or 0) + (result.secureCount or 0)
    return result
end

function Polish:GetBadges(result)
    if type(result) ~= "table" then return "" end
    local badges = {}
    local risk = lower(result.riskClass or "")
    if self:GetSourceUsageCount(result) > 0 then badges[#badges + 1] = "SRC" end
    if self:GetExampleCount(result) > 0 then badges[#badges + 1] = "EX" end
    if self:GetSecureCount(result) > 0 then badges[#badges + 1] = "SEC" end
    if contains(risk, "protected") or contains(risk, "blocked") then badges[#badges + 1] = "BLOCKED" end
    if contains(risk, "inspect") or contains(risk, "metadata") then badges[#badges + 1] = "INSPECT" end
    if contains(risk, "review") then badges[#badges + 1] = "REVIEW" end
    return table.concat(badges, " ")
end

function Polish:GetRowSuffix(result)
    local badges = self:GetBadges(result)
    local count = tonumber(result and result.relationshipCount or 0) or 0
    local suffix = ""
    if badges ~= "" then suffix = suffix .. " |cff777777[" .. badges .. "]|r" end
    if count > 0 then suffix = suffix .. " |cff666666links:" .. tostring(count) .. "|r" end
    return suffix
end

function Polish:AppendRelationshipCard(text, result)
    if type(result) ~= "table" then return text end
    text = ApiVault:AppendLine(text, "")
    text = ApiVault:AppendLine(text, "Relationship card:")
    text = ApiVault:AppendLine(text, "- badges: " .. tostring(self:GetBadges(result) ~= "" and self:GetBadges(result) or "none"))
    text = ApiVault:AppendLine(text, "- source usage refs: " .. tostring(self:GetSourceUsageCount(result)))
    text = ApiVault:AppendLine(text, "- source examples: " .. tostring(self:GetExampleCount(result)))
    text = ApiVault:AppendLine(text, "- secure pattern refs: " .. tostring(self:GetSecureCount(result)))
    text = ApiVault:AppendLine(text, "- quick actions: /av polish, /av export, /av favorites")
    text = ApiVault:AppendLine(text, "- policy: generated metadata only; no runtime file reads; no protected/secure execution")
    return text
end

function Polish:BuildQuickSummary(result)
    result = self:NormalizeContext(result or self.currentContext)
    if not result then return "No context selected." end
    local lines = {}
    lines[#lines + 1] = "ApiVault quick summary"
    lines[#lines + 1] = "- item: " .. tostring(displayOf(result))
    lines[#lines + 1] = "- category: " .. tostring(result.category or "?")
    lines[#lines + 1] = "- kind: " .. tostring(result.kind or "?")
    lines[#lines + 1] = "- module: " .. tostring(result.module or "")
    lines[#lines + 1] = "- riskClass: " .. tostring(result.riskClass or "")
    lines[#lines + 1] = "- badges: " .. tostring(self:GetBadges(result))
    lines[#lines + 1] = "- source usage refs: " .. tostring(self:GetSourceUsageCount(result))
    lines[#lines + 1] = "- examples: " .. tostring(self:GetExampleCount(result))
    lines[#lines + 1] = "- secure refs: " .. tostring(self:GetSecureCount(result))
    lines[#lines + 1] = "- note: metadata-backed; verify behavior in-game when runtime context matters."
    return table.concat(lines, "\n")
end

function Polish:BuildQuickAuditNote(result)
    result = self:NormalizeContext(result or self.currentContext)
    if not result then return "No context selected." end
    local lines = {}
    lines[#lines + 1] = "ApiVault audit note"
    lines[#lines + 1] = "Subject: " .. tostring(displayOf(result))
    lines[#lines + 1] = "Classification: " .. tostring(result.category or "?") .. " / " .. tostring(result.kind or "?")
    lines[#lines + 1] = "Risk: " .. tostring(result.riskClass or "")
    lines[#lines + 1] = "Source usage refs: " .. tostring(self:GetSourceUsageCount(result))
    lines[#lines + 1] = "Source examples: " .. tostring(self:GetExampleCount(result))
    lines[#lines + 1] = "Secure patterns: " .. tostring(self:GetSecureCount(result))
    lines[#lines + 1] = "Required validation: confirm in live WoW client, out-of-combat and combat where relevant."
    lines[#lines + 1] = "Policy: no automatic protected/secure execution; no runtime source reads."
    return table.concat(lines, "\n")
end

function Polish:BuildTestChecklist(result)
    result = self:NormalizeContext(result or self.currentContext)
    local subject = result and displayOf(result) or "<none>"
    local lines = {}
    lines[#lines + 1] = "ApiVault test checklist: " .. tostring(subject)
    lines[#lines + 1] = "[ ] Confirm item is documented or source-backed."
    lines[#lines + 1] = "[ ] Review riskClass and inspect-only badges."
    lines[#lines + 1] = "[ ] Check source usage and generated examples."
    lines[#lines + 1] = "[ ] Check secure pattern references."
    lines[#lines + 1] = "[ ] If Function: verify SafeRunner allows execution before testing."
    lines[#lines + 1] = "[ ] If Event: listen manually and cap payload logs."
    lines[#lines + 1] = "[ ] If Template/Module/File: inspect metadata only; do not assume safe usage."
    lines[#lines + 1] = "[ ] Test out of combat."
    lines[#lines + 1] = "[ ] Test combat behavior only if relevant and safe."
    lines[#lines + 1] = "[ ] Mark undocumented behavior as UNCERTAIN."
    return table.concat(lines, "\n")
end

function Polish:OpenRelated(result)
    result = self:NormalizeContext(result or self.currentContext)
    if not result then return false, "No context selected." end
    local category = result.category
    if category == "API" and ApiVault.UI and ApiVault.UI.Toggle then ApiVault.UI:Toggle(); return true, "API browser opened" end
    if category == "Resource" and ApiVault.InterfaceBrowser and ApiVault.InterfaceBrowser.Toggle then ApiVault.InterfaceBrowser:Toggle(); return true, "Interface browser opened" end
    if category == "XML" and ApiVault.XMLTemplateBrowser and ApiVault.XMLTemplateBrowser.Toggle then ApiVault.XMLTemplateBrowser:Toggle(); return true, "XML browser opened" end
    if category == "Module" and ApiVault.ModuleBrowser and ApiVault.ModuleBrowser.Toggle then ApiVault.ModuleBrowser:Toggle(); return true, "Module browser opened" end
    if category == "Example" and ApiVault.SourceExampleBrowser and ApiVault.SourceExampleBrowser.Toggle then ApiVault.SourceExampleBrowser:Toggle(); return true, "Source example browser opened" end
    if category == "Secure" and ApiVault.SecurePatternBrowser and ApiVault.SecurePatternBrowser.Toggle then ApiVault.SecurePatternBrowser:Toggle(); return true, "Secure pattern browser opened" end
    if category == "Symbol" and ApiVault.SymbolBrowser and ApiVault.SymbolBrowser.Toggle then ApiVault.SymbolBrowser:Toggle(); return true, "Symbol browser opened" end
    return false, "No related browser available for " .. tostring(category)
end

function Polish:ToggleFavorite(result)
    result = self:NormalizeContext(result or self.currentContext)
    if not result or not ApiVault.UserState then return false, "favorites unavailable" end
    local added, key = ApiVault.UserState:ToggleFavorite(result, "TodoCompletion")
    return added, key
end

function Polish:SetCompactMode(enabled)
    if ApiVault.UserState and ApiVault.UserState.SetSetting then
        ApiVault.UserState:SetSetting("compactMode", enabled and true or false)
    else
        ApiVaultDB = type(ApiVaultDB) == "table" and ApiVaultDB or {}
        ApiVaultDB.settings = type(ApiVaultDB.settings) == "table" and ApiVaultDB.settings or {}
        ApiVaultDB.settings.compactMode = enabled and true or false
    end
end

function Polish:IsCompactMode()
    if ApiVault.UserState and ApiVault.UserState.GetSetting then
        return ApiVault.UserState:GetSetting("compactMode", false) and true or false
    end
    return type(ApiVaultDB) == "table" and type(ApiVaultDB.settings) == "table" and ApiVaultDB.settings.compactMode and true or false
end

function Polish:WrapGlobalSearch()
    local Search = ApiVault.GlobalSearch
    if not Search or Search.todoCompletionWrapped or type(Search.Search) ~= "function" then return end
    local originalSearch = Search.Search
    local originalDescribe = Search.DescribeResult
    Search.todoCompletionWrapped = true
    function Search:Search(query, filter, limit)
        if ApiVault.TodoCompletion and ApiVault.TodoCompletion:IsAdvancedFilter(filter) then
            local base = originalSearch(self, query, "All", math.min((tonumber(limit) or 350) * 3, 900)) or {}
            return ApiVault.TodoCompletion:FilterResults(base, filter, limit or 350)
        end
        local results = originalSearch(self, query, filter, limit) or {}
        for _, result in ipairs(results) do
            ApiVault.TodoCompletion:DecorateResult(result)
        end
        return results
    end
    if type(originalDescribe) == "function" then
        function Search:DescribeResult(result)
            local text = originalDescribe(self, result)
            if ApiVault.TodoCompletion then
                text = ApiVault.TodoCompletion:AppendRelationshipCard(text, result)
            end
            return text
        end
    end
end

Polish:WrapGlobalSearch()
