local ADDON_NAME, WDIGI = ...
WDIGI.Tooltip = WDIGI.Tooltip or {}

local VT = WDIGI.Data.VENDOR_TYPE

------------------------------------------------------------
-- CATEGORY DEFINITIONS
------------------------------------------------------------
WDIGI.Tooltip.CATEGORIES = {
    { vendorType = VT.DROPPED_BY,        header = "|cff00ff00What Drops This?|r",       setting = "WDIGI_Limit_DroppedBy" },
    { vendorType = VT.SOLD_BY,           header = "|cffffff00Who Sells This?|r",        setting = "WDIGI_Limit_SoldBy" },
    { vendorType = VT.CONTAINED_IN,      header = "|cff00ffffContained In?|r",          setting = "WDIGI_Limit_ContainedIn" },
    { vendorType = VT.DISENCHANTED_FROM, header = "|cffc080ffDisenchanted From?|r",     setting = "WDIGI_Limit_Disenchanted" },
    { vendorType = VT.GATHERED_FROM,     header = "|cffff8000Gathered From?|r",         setting = "WDIGI_Limit_GatheredFrom" },
    { vendorType = VT.CRAFTED_BY,        header = "|cffeda55fCrafted By?|r",            setting = "WDIGI_Limit_CraftedBy" },
    { vendorType = VT.LEARNED_FROM,      header = "|cffabd473Learned From?|r",          setting = "WDIGI_Limit_LearnedFrom" },
    { vendorType = VT.QUEST_REWARD,      header = "|cffffcc00Quest Reward?|r",          setting = "WDIGI_Limit_QuestReward" },    
    { vendorType = VT.UNKNOWN,           header = "|cffaaaaaaOther Sources?|r",         setting = "WDIGI_Limit_Other" }
}

------------------------------------------------------------
-- MAIN TOOLTIP UPDATE
------------------------------------------------------------
function WDIGI.Tooltip.Update(tooltip)
    -- 1. CLOAKING DEVICE: Only allow GameTooltip and ItemRefTooltip.
    -- This ignores ShoppingTooltips and prevents the "nil value" error.
    if tooltip ~= GameTooltip and tooltip ~= ItemRefTooltip then 
        return 
    end

    -- 2. Forbidden checks (Standard Blizzard protection)
    if not tooltip or tooltip:IsForbidden() then return end

    -- 3. Modern Item Check
    -- Using the newer C_TooltipInfo check is safer for the 2026 client
    local _, itemLink = tooltip:GetItem()
    if not itemLink then return end

    local _, itemLink = tooltip:GetItem()
    if not itemLink then return end

    local itemID = GetItemInfoFromHyperlink(itemLink)
    -- Check if we actually have data for this item in our database
    if not itemID or not ITEMLOCATIONSLIST[itemID] then return end

    -- Respect user ALT-key toggle setting
    if WDIGI.Settings.Get("WDIGI_ALTKey_Toggle") and not IsAltKeyDown() then return end

    -- Data Latency Guard: Return early if GetItemInfo hasn't cached the item yet.
    -- WoW will automatically re-fire the tooltip event once the data arrives.
    local itemName, _, _, _, _, _, _, _, _, itemIcon = GetItemInfo(itemLink)
    if not itemName then return end

    WDIGI.Tooltip.lastItemName = itemName
    WDIGI.Tooltip.lastItemIcon = itemIcon
    WDIGI.Tooltip.bestLocation = nil
    
    local linesAdded = false
    local firstCategory = true

    for _, cat in ipairs(WDIGI.Tooltip.CATEGORIES) do
        local best = WDIGI.Tooltip.AddCategory(
            tooltip,
            itemID,
            cat.vendorType,
            cat.header,
            cat.setting,
            firstCategory
        )

        if best then
            linesAdded = true
            -- Track the absolute closest source for the Ctrl+Shift click feature
            if (not WDIGI.Tooltip.bestLocation or best.dist < WDIGI.Tooltip.bestLocation.dist) then
                WDIGI.Tooltip.bestLocation = best
                WDIGI.Tooltip.bestLocation.header = cat.header
            end
        end

        firstCategory = false
    end

    -- THE FLICKER FIX: If we added content, force the tooltip to recalculate its
    -- layout immediately so it doesn't "pop" or "jitter" after rendering.
    if linesAdded then
        tooltip:Show()
    end
end

------------------------------------------------------------
-- CATEGORY RENDERING
------------------------------------------------------------
function WDIGI.Tooltip.AddCategory(tooltip, itemID, vendorType, header, setting, firstCategory)
    local entries = WDIGI.Data.ParseItemData(itemID)
    if #entries == 0 then return nil end

    local myMapID, px, py = WDIGI.MapUtils.GetCurrentPlayerData()
    local results = {}

    --------------------------------------------------------
    -- Build vendor entries and calculate distance
    --------------------------------------------------------
    for _, e in ipairs(entries) do
        if e.vendorType == vendorType then
            local matchLevel = WDIGI.MapUtils.GetZoneMatchLevel(myMapID, e.mapID)
            local onMap = (matchLevel == 0 or matchLevel == 1)
            local dist = 999999

            if onMap and px and py and e.tx > 0 and e.ty > 0 then
                local dx = (e.tx / 100) - px
                local dy = (e.ty / 100) - py
                dist = math.sqrt(dx * dx + dy * dy) * (WDIGI.MapUtils.GetZoneMultiplier() or 1000)
            end

            table.insert(results, {
                dist       = dist,
                onMap      = onMap,
                matchLevel = matchLevel,
                zID        = e.mapID,
                parentID   = e.parentMapID,
                tx         = e.tx,
                ty         = e.ty,
                vendorName = e.vendorName,
                vendorType = e.vendorType,
                cost       = e.costString
            })
        end
    end

    if #results == 0 then return nil end

    --------------------------------------------------------
    -- Smart Filtering: Only show the "best" geographic match
    --------------------------------------------------------
    local bestLevel = 3
    for _, r in ipairs(results) do
        if r.matchLevel < bestLevel then bestLevel = r.matchLevel end
    end

    local filtered = {}
    for _, r in ipairs(results) do
        if r.matchLevel == bestLevel then
            table.insert(filtered, r)
        end
    end
    results = filtered

    -- Sort: On same map first, then by physical distance
    table.sort(results, function(a, b)
        if a.onMap ~= b.onMap then return a.onMap end
        return a.dist < b.dist
    end)

    --------------------------------------------------------
    -- Tooltip Injection
    --------------------------------------------------------
    if WDIGI.Settings.Get("WDIGI_ShowItemID_Toggle") and firstCategory then
        tooltip:AddLine("|cffff0000Item ID:|r " .. itemID)
    end

    tooltip:AddLine("\n" .. header)

    local limit = WDIGI.Settings.Get(setting) or 5
    for i = 1, math.min(limit, #results) do
        local r = results[i]
        
        -- Get Zone Name with Parent Fallback
        local mapInfo = C_Map.GetMapInfo(r.zID or 0) or (r.parentID and C_Map.GetMapInfo(r.parentID))
        local zoneName = mapInfo and mapInfo.name or (r.vendorType == VT.DROPPED_BY and "World Drop" or "Unknown Location")
        local isFallback = not mapInfo
        
        local icon = WDIGI.Data.VENDOR_ICONS[r.vendorType]
        local iconTag = icon and ("|T" .. icon .. ":14:14:0:0|t ") or ""
        local zoneColor = isFallback and "|cff9d9d9d" or "|cff80ff80"
        
        local locationText = zoneColor .. zoneName .. "|r"
        if r.tx > 0 and r.ty > 0 then
            locationText = locationText .. string.format(" (|cffffff00%.1f, %.1f|r)", r.tx, r.ty)
        end

        local line = string.format("  %s|cffffffff%s|r - %s", iconTag, r.vendorName, locationText)
        
        -- Append distance only if on a relevant map
        if r.onMap and r.dist < 5000 and r.tx > 0 then
            line = line .. " |cff32ff32(" .. math.floor(r.dist) .. "yd)|r"
        end

        tooltip:AddLine(line)
    end

    return results[1]
end