--[[
============================================================================
ETB - NPCSourceTooltip.lua
============================================================================
Appends transmog sources to NPC mouseover tooltips for NPCs that ETB's boss
index intentionally skips: VENDORS (sell appearances/plans), TRAINERS (teach
crafted appearances), and QUEST-GIVERS (whose quests reward appearances).

Data: ETB.NPCSources[npcID] = { v = {itemIDs}, t = {itemIDs}, q = {itemIDs} }
  v = vendor-sold   t = trainer-taught   q = quest-reward
Built offline from AllTheThings 5.1.7 (May 2026 cross-check).

Style matches Modules/BossLootTooltip/Render.lua: gold section headers with an
X/Y collected count, quality-coloured item names, green check for owned.
============================================================================
]]--

local ADDON_NAME, NS = ...
local ETB = NS.ETB
local S = (ETB and ETB.Style) or {}
ETB.NPCSourceTooltip = ETB.NPCSourceTooltip or {}
local M = ETB.NPCSourceTooltip

-- Slots that carry no visible transmog appearance (match BossLootTooltip filter)
local EXCLUDED_EQUIP_LOCS = {
    INVTYPE_FINGER = true, INVTYPE_TRINKET = true, INVTYPE_NECK = true,
    INVTYPE_BAG = true, INVTYPE_AMMO = true, INVTYPE_QUIVER = true,
    INVTYPE_RELIC = true, INVTYPE_NON_EQUIP = true,
}
-- Item classes that can hold an appearance (2 = weapon, 4 = armor)
local VALID_ITEM_CLASSES = { [2] = true, [4] = true }

local MAX_PER_SECTION = 12   -- keep tooltips reasonable

local SECTIONS = {
    { key = "v", header = "Sells Transmog" },
    { key = "t", header = "Teaches (Profession)" },
    { key = "q", header = "Quest Reward" },
}

-- Owned-state resolver: prefer ETB's CollectionAPI, fall back to Blizzard API.
local function IsCollected(itemID)
    if ETB.CollectionAPI and ETB.CollectionAPI.GetState then
        local ok, state = pcall(ETB.CollectionAPI.GetState, ETB.CollectionAPI, itemID)
        if ok and state ~= nil then
            -- GetState returns a truthy "collected"/"known" state
            if state == true or state == "collected" or state == "known" then return true end
            if state == false or state == "missing" then return false end
        end
    end
    local hasInstant, _, _, equipLoc, icon, classID = GetItemInfoInstant(itemID)
    if C_TransmogCollection and C_TransmogCollection.GetItemInfo then
        local catID, srcID = C_TransmogCollection.GetItemInfo(itemID)
        if srcID and C_TransmogCollection.PlayerHasTransmogItemModifiedAppearance then
            local ok, has = pcall(C_TransmogCollection.PlayerHasTransmogItemModifiedAppearance, srcID)
            if ok then return has end
        end
    end
    return nil  -- unknown
end

-- Keep only items that carry a visible appearance (filter rings/trinkets/etc.).
-- Unknown/uncached items are kept (they may not be cached yet).
local function isVisibleAppearance(itemID)
    local _, _, _, equipLoc, _, classID = GetItemInfoInstant(itemID)
    if classID and not VALID_ITEM_CLASSES[classID] then return false end
    if equipLoc and EXCLUDED_EQUIP_LOCS[equipLoc] then return false end
    return true
end

local function qualityColor(itemID)
    local _, _, quality = GetItemInfo(itemID)
    if quality and ITEM_QUALITY_COLORS and ITEM_QUALITY_COLORS[quality] then
        return ITEM_QUALITY_COLORS[quality].hex or "|cffffffff"
    end
    return "|cffffffff"
end

local lastNPC  -- de-dupe guard within a single mouseover population

function M:Append(tooltip, npcID)
    if not npcID then return end
    local data = ETB.NPCSources and ETB.NPCSources[npcID]
    if not data then return end
    if tooltip ~= GameTooltip then return end

    for _, section in ipairs(SECTIONS) do
        local list = data[section.key]
        if list and #list > 0 then
            -- Filter to visible appearances and compute collected count.
            local shown, collected = {}, 0
            for _, itemID in ipairs(list) do
                if isVisibleAppearance(itemID) then
                    local owned = IsCollected(itemID)
                    shown[#shown + 1] = { id = itemID, owned = owned }
                    if owned == true then collected = collected + 1 end
                end
            end

            if #shown > 0 then
                tooltip:AddLine(" ")
                tooltip:AddDoubleLine(
                    (S.HEADER or "|cff00ccff") .. "ETB: " .. section.header .. "|r",
                    (S.Count and S:Count(collected, #shown))
                        or string.format("|cff00ff00%d|r|cffaaaaaa/%d|r", collected, #shown)
                )

                local limit = math.min(#shown, MAX_PER_SECTION)
                for i = 1, limit do
                    local e = shown[i]
                    local name = GetItemInfo(e.id) or ("item:" .. e.id)
                    local line = qualityColor(e.id) .. name .. "|r"
                    local mark
                    if e.owned == true then
                        mark = S.MARK_OWNED or "|TInterface\\RaidFrame\\ReadyCheck-Ready:14:14:0:0|t"
                    elseif e.owned == false then
                        mark = S.MARK_MISSING or "|TInterface\\RaidFrame\\ReadyCheck-NotReady:14:14:0:0|t"
                    else
                        mark = "|cff808080?|r"                       -- unknown/uncached
                    end
                    tooltip:AddDoubleLine("  " .. line, mark)
                end
                if #shown > limit then
                    tooltip:AddLine(string.format("|cff808080  ...and %d more|r", #shown - limit))
                end
            end
        end
    end

    tooltip:Show()  -- recalc size after adding lines
end

ETB:Debug("NPCSourceTooltip", "loaded")
