--[[
ETB CollectionTooltip — the one consolidated "appearance collected / NOT
collected (+ source)" section on item tooltips.

Pervasive by design: it hooks the shared item tooltips (GameTooltip,
ItemRefTooltip, the two ShoppingTooltips) plus — defensively — the Encounter
Journal tooltip. On this client almost every item hover routes through
GameTooltip, so bags, merchants, loot windows and quest-reward buttons are all
covered by the GameTooltip hook; the extra EJ hook closes the one surface that
can use its own tooltip frame.

Two correctness properties this module guarantees:
  * ONE section per render. OnTooltipSetItem can fire more than once for a
    single tooltip render on some clients; a per-tooltip guard (reset by
    OnTooltipCleared, which fires before every fresh SetX) makes the append
    idempotent so the block can never be duplicated.
  * Owned/MISSING + SOURCE. For a missing appearance we show where to get it
    (boss/instance via SourceLookup) in both compact and detailed modes — the
    actionable half of "Can I mog it?".

The verbose breakdown (full source list, crafting, BiS rank, etc.) still lives
in the side panel (TooltipEnhancer); this inline block stays deliberately tight.
]]--
local ADDON_NAME, NS = ...
local ETB = NS.ETB

ETB.CollectionTooltip = {}
local CT = ETB.CollectionTooltip
CT.enabled = true

-- Wishlist star (texture renders reliably).
local STAR = "|TInterface\\Common\\ReputationStar:14:14:0:0|t"

-- Collected/missing marks from the shared style (ReadyCheck textures render
-- reliably; read lazily so load order with TooltipStyle never matters). Falls
-- back to unicode glyphs if the style somehow isn't present.
local function marks()
    local S = ETB.Style or {}
    return S.MARK_OWNED   or "|cff00ff00\226\156\147|r",
           S.MARK_MISSING or "|cffff4444\226\156\151|r"
end

-- Concise source string for a missing appearance. Boss/instance/difficulty via
-- SourceLookup, which is already on the tooltip path and self-caches. Returns
-- nil when unknown (vendor/quest/profession source is a planned follow-up — it
-- lives in the lazily-deferred NPCSources table, which we deliberately don't
-- force-materialise just to render a tooltip line).
local function ResolveSource(itemID)
    if ETB.IsLowMemoryMode and ETB:IsLowMemoryMode() then
        return nil
    end
    if ETB.SourceLookup and ETB.SourceLookup.GetSourceText then
        local ok, txt = pcall(ETB.SourceLookup.GetSourceText, ETB.SourceLookup, itemID)
        if ok and txt and txt ~= "" then return txt end
    end
    return nil
end

local function isCompact()
    if ETB.Settings and ETB.Settings.Get then
        local v = ETB.Settings:Get("tooltips.compact")
        if v ~= nil then return v and true or false end
    end
    return true  -- compact by default
end

local function OnTooltipSetItem(tooltip)
    if not CT.enabled then return end
    -- Idempotent per render: bail if we've already added our block to this
    -- tooltip since it was last cleared.
    if tooltip._etbCollDone then return end

    local _, link = tooltip:GetItem()
    if not link then return end
    local itemID = tonumber(link:match("item:(%d+)"))
    if not itemID then return end

    -- Cheap early-out: only equippable items (2=Weapon, 4=Armor) can carry an
    -- appearance. Skips GetState calls on the flood of non-equippable hovers.
    local _, _, _, _, _, classID = GetItemInfoInstant(itemID)
    if not classID or (classID ~= 2 and classID ~= 4) then return end

    -- One shared collection resolver for both this inline block and the side
    -- panel: CollectionAPI:GetState (cached, MoP per-armor-type aware).
    local CAPI = ETB.CollectionAPI
    if not CAPI then return end
    local state = CAPI:GetState(itemID)
    -- nil  → not loaded yet (re-fires on GET_ITEM_INFO_RECEIVED); skip cleanly.
    -- NO_APPEARANCE → item isn't transmoggable; nothing to show.
    if not state or state == "NO_APPEARANCE" then return end

    -- Commit: from here we add exactly one block; guard against re-entry.
    tooltip._etbCollDone = true

    local onWishlist, wlAnchor, wlDirect = false, nil, false
    if ETB.Wishlist and ETB.Wishlist.HasAppearance then
        onWishlist, wlAnchor, wlDirect = ETB.Wishlist:HasAppearance(itemID)
    elseif ETB.Wishlist then
        onWishlist = ETB.Wishlist:HasItem(itemID); wlDirect = onWishlist
    end
    local compact = isCompact()
    local OWNED, MISSING = marks()
    -- The actionable half of "can I mog it?": where to get a missing appearance.
    local missingish = (state == "NOT_COLLECTED" or state == "KNOWN_OTHER_DIFFERENT_ARMOR")

    tooltip:AddLine(" ")
    if state == "COLLECTED" then
        tooltip:AddLine(OWNED .. " |cff00ff00Appearance collected|r")
    elseif state == "KNOWN_OTHER" then
        tooltip:AddLine(OWNED .. " |cff66ccffKnown from another item|r")
    elseif state == "KNOWN_OTHER_DIFFERENT_ARMOR" then
        tooltip:AddLine("|cffff9900\226\154\160 Appearance only from a different armor type|r")
    else  -- NOT_COLLECTED
        local head = MISSING .. " |cffff6666Appearance NOT collected|r"
        if onWishlist then head = head .. "  " .. STAR end  -- inline star
        tooltip:AddLine(head)
    end

    -- Owned/MISSING + SOURCE: show where to get it, in BOTH compact and detailed.
    if missingish then
        local src = ResolveSource(itemID)
        if src then tooltip:AddLine("|cff888888Source: " .. src .. "|r") end
    end

    -- Detailed mode adds an explicit wishlist line (besides the inline star).
    if not compact and onWishlist and missingish then
        if wlDirect then
            tooltip:AddLine("|cffffcc00On your wishlist|r")
        else
            local an = wlAnchor and GetItemInfo and GetItemInfo(wlAnchor)
            if an then
                tooltip:AddLine("|cffffcc00Same look as wishlisted " .. an .. "|r")
            else
                tooltip:AddLine("|cffffcc00Same look as a wishlisted item|r")
            end
        end
    end

    tooltip:Show()
end

-- Reset the per-render guard when a tooltip is cleared (fires before every new
-- SetX), so the next item gets its section and double-fires of the same render
-- do not.
local function OnTooltipCleared(tooltip)
    tooltip._etbCollDone = nil
end

local function Install(tip)
    if not tip or tip._etbCollHooked then return end
    tip._etbCollHooked = true
    tip:HookScript("OnTooltipSetItem", OnTooltipSetItem)
    tip:HookScript("OnTooltipCleared", OnTooltipCleared)
end

function CT:Initialize()
    Install(GameTooltip)
    Install(ItemRefTooltip)
    Install(ShoppingTooltip1)
    Install(ShoppingTooltip2)

    -- The Encounter Journal is a load-on-demand Blizzard addon, so its tooltip
    -- frame doesn't exist at login. EJ loot items hover through GameTooltip
    -- (already hooked above), but in case a build routes them through the EJ's
    -- own frame, attach there too the moment the EJ loads. If it's already
    -- loaded, install immediately.
    local isLoaded = (C_AddOns and C_AddOns.IsAddOnLoaded) or IsAddOnLoaded
    if isLoaded and isLoaded("Blizzard_EncounterJournal") then
        Install(_G.EncounterJournalTooltip)
    else
        local w = CreateFrame("Frame")
        w:RegisterEvent("ADDON_LOADED")
        w:SetScript("OnEvent", function(self, _, name)
            if name == "Blizzard_EncounterJournal" then
                Install(_G.EncounterJournalTooltip)
                self:UnregisterEvent("ADDON_LOADED")
            end
        end)
    end

    ETB:Debug("CollectionTooltip", "Consolidated collection-status tooltip hooks installed")
end
