-- compendium.lua (v1.6.5 - The "Era Badge" Edition)
local ADDON_NAME, WDIGI = ...
WDIGI.Compendium = WDIGI.Compendium or {}

local SIDEBAR_WIDTH = 220 
local ROW_HEIGHT = 36 

local COLORS = {
    BG_MAIN         = {0.07, 0.07, 0.08, 0.98},
    BG_SIDEBAR      = {0.10, 0.10, 0.12, 1.00},
    BG_HDR_ZONE     = {0.11, 0.15, 0.24, 1.00},
    BG_HDR_SUBTYPE  = {0.15, 0.15, 0.17, 1.0},
    AMBER_TEXT      = {1.00, 0.70, 0.00, 1.00},
    TEXT_DIM        = {0.50, 0.50, 0.55, 1.00},
    BORDER          = {0.20, 0.20, 0.22, 1.00},
    CARD_BG         = {0.05, 0.05, 0.06, 1.00},
}

local ENTITY_ICONS = {
    ITEM = 133633,
    NPC  = 135911,
    ZONE = 132320,
}

WDIGI.Data.VENDOR_TYPE_NAMES = {
    [1] = "Sold by", [2] = "Source", [3] = "Contained in",
    [4] = "Disenchanted from", [5] = "Gathered from", [6] = "Crafted by",
    [7] = "Learned from", [8] = "Quest Reward", [99] = "Source",
}

local VT = WDIGI.Data.VENDOR_TYPE
WDIGI.Data.VENDOR_ICONS = {
    [VT.SOLD_BY]           = 133633, [VT.DROPPED_BY]        = 132318,
    [VT.CRAFTED_BY]        = 136240, [VT.LEARNED_FROM]      = 135894,
    [VT.CONTAINED_IN]      = 132594, [VT.DISENCHANTED_FROM] = 236207,
    [VT.GATHERED_FROM]     = 134187, [VT.QUEST_REWARD]      = 132320,
    [VT.UNKNOWN]           = 134400,
}

------------------------------------------------------------
-- MINIMAP BUTTON
------------------------------------------------------------
function WDIGI.Compendium:CreateMinimapButton()
    if not WDIGI.Settings.Get("WDIGI_EnableCompendium_Experimental") then return end
    if WDIGI_MinimapButton then return end
    
    local btn = CreateFrame("Button", "WDIGI_MinimapButton", Minimap)
    btn:SetSize(31, 31); btn:SetFrameLevel(8); btn:SetToplevel(true)
    btn:RegisterForClicks("LeftButtonUp")
    
    local icon = btn:CreateTexture(nil, "BACKGROUND")
    icon:SetTexture(ENTITY_ICONS.ITEM) 
    icon:SetSize(20, 20); icon:SetPoint("CENTER", 0, 0)
    
    local border = btn:CreateTexture(nil, "OVERLAY")
    border:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder")
    border:SetSize(53, 53); border:SetPoint("TOPLEFT", 0, 0)
    
    btn:SetPoint("TOPLEFT", Minimap, "TOPLEFT", -5, -5)
    btn:SetScript("OnClick", function() self:Toggle() end)
    
    btn:SetMovable(true); btn:RegisterForDrag("LeftButton")
    btn:SetScript("OnDragStart", btn.StartMoving); btn:SetScript("OnDragStop", btn.StopMovingOrSizing)
end

------------------------------------------------------------
-- WINDOW CREATION
------------------------------------------------------------
function WDIGI.Compendium:Create()
    if self.Frame then return end
    local scale = 1.4 
    self.Scale = scale

    local f = CreateFrame("Frame", "WDIGI_Compendium", UIParent, "BackdropTemplate")
    f:SetSize(765, 520); f:SetPoint("LEFT"); f:SetMovable(true); f:EnableMouse(true); f:SetScale(scale)
    f:SetFrameStrata("HIGH"); f:SetToplevel(true)
    f:RegisterForDrag("LeftButton"); f:SetScript("OnDragStart", f.StartMoving); f:SetScript("OnDragStop", f.StopMovingOrSizing)
    
    f:SetBackdrop({bgFile = "Interface\\Buttons\\WHITE8X8", edgeFile = "Interface\\Buttons\\WHITE8X8", edgeSize = 1})
    f:SetBackdropColor(unpack(COLORS.BG_MAIN)); f:SetBackdropBorderColor(unpack(COLORS.BORDER))
    self.Frame = f

    -- TOOLBAR
    local toolbar = CreateFrame("Frame", nil, f, "BackdropTemplate")
    toolbar:SetSize(f:GetWidth() - 10, 40); toolbar:SetPoint("TOPLEFT", 5, -5)
    toolbar:SetBackdrop({bgFile = "Interface\\Buttons\\WHITE8X8"})
    toolbar:SetBackdropColor(0.05, 0.05, 0.06, 1)

    -- ICON: Using the defined constant and explicit parenting
    local titleIcon = toolbar:CreateTexture(nil, "OVERLAY")
    titleIcon:SetSize(32, 32)
    titleIcon:SetPoint("LEFT", 5, 0)
    titleIcon:SetTexture(ENTITY_ICONS.ITEM) -- Ensure this is 133633
    titleIcon:SetDesaturated(true)
    titleIcon:SetAlpha(0.7)

    -- TITLE: Centered with Amber Yellow text
    local titleText = toolbar:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    titleText:SetPoint("RIGHT", -35, 2)
    titleText:SetText("COMPENDIUM")
    titleText:SetTextColor(unpack(COLORS.AMBER_TEXT)) -- Amber Yellow {1.0, 0.7, 0.0}

    -- SEARCH FIELD: Re-anchored to the RIGHT of the Icon
    local eb = CreateFrame("EditBox", nil, toolbar, "BackdropTemplate")
    eb:SetSize(SIDEBAR_WIDTH - 55, 24)
    eb:SetPoint("LEFT", titleIcon, "RIGHT", 10, 0) -- This prevents the overlap
    eb:SetAutoFocus(false)
    eb:SetFontObject("ChatFontNormal")
    eb:SetTextInsets(10, 10, 0, 0)
    eb:SetBackdrop({bgFile = "Interface\\Buttons\\WHITE8X8", edgeFile = "Interface\\Buttons\\WHITE8X8", edgeSize = 1})
    eb:SetBackdropColor(0.02, 0.02, 0.02, 1); eb:SetBackdropBorderColor(0.3, 0.3, 0.3, 1)   
    
    eb:SetScript("OnTextChanged", function(this, userInput)
        if not userInput then return end
        local query = this:GetText():trim()
        if #query < 3 then return end
        if this.timer then this.timer:Cancel() end
        this.timer = C_Timer.NewTimer(0.4, function() WDIGI.Compendium:PerformSearch(query) end)
    end)
    self.SearchBox = eb

    -- 2. Action Buttons
    local resetBtn = CreateFrame("Button", nil, toolbar, "BackdropTemplate")
    resetBtn:SetSize(55, 24); resetBtn:SetPoint("LEFT", eb, "RIGHT", 6, 0)
    resetBtn:SetBackdrop({bgFile = "Interface\\Buttons\\WHITE8X8", edgeFile = "Interface\\Buttons\\WHITE8X8", edgeSize = 1})
    resetBtn:SetBackdropColor(0.15, 0.15, 0.18, 1); resetBtn:SetBackdropBorderColor(0.3, 0.3, 0.3, 1)
    local rt = resetBtn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    rt:SetText("CLEAR"); rt:SetPoint("CENTER", 0, 0); rt:SetTextColor(0.8, 0.8, 0.8)
    resetBtn:SetScript("OnClick", function() 
        eb:SetText(""); WDIGI.Compendium.LastQuery = ""
        WDIGI.Compendium:SetDetailLayout(false)
        
        -- Fix: Check if rows exist before iterating
        if WDIGI.Compendium.ListRows then
            for _, row in ipairs(WDIGI.Compendium.ListRows) do row:Hide() end
        end
        if WDIGI.Compendium.DetailRows then
            for _, row in ipairs(WDIGI.Compendium.DetailRows) do row:Hide() end
        end
        
        if WDIGI.Compendium.SplashFrame then WDIGI.Compendium.SplashFrame:Show() end
    end)

    -- REFRESH BUTTON
    local refreshBtn = CreateFrame("Button", nil, toolbar, "BackdropTemplate")
    refreshBtn:SetSize(24, 24); refreshBtn:SetPoint("LEFT", resetBtn, "RIGHT", 4, 0)
    refreshBtn:SetBackdrop({bgFile = "Interface\\Buttons\\WHITE8X8", edgeFile = "Interface\\Buttons\\WHITE8X8", edgeSize = 1})
    refreshBtn:SetBackdropColor(0.15, 0.15, 0.18, 1); refreshBtn:SetBackdropBorderColor(0.3, 0.3, 0.3, 1)

    -- New Texture Logic
    local rfIcon = refreshBtn:CreateTexture(nil, "OVERLAY")
    rfIcon:SetTexture("Interface\\Buttons\\UI-RefreshButton")
    rfIcon:SetSize(16, 16)
    rfIcon:SetPoint("CENTER", 0, 0)
    rfIcon:SetVertexColor(0, 0.8, 1.0) 

    -- REMOVED: rft:SetText... (This was causing the crash)

    refreshBtn:SetScript("OnClick", function() 
        local query = eb:GetText()
        if #query >= 3 then WDIGI.Compendium.LastQuery = ""; WDIGI.Compendium:PerformSearch(query) end
    end)

    refreshBtn:SetScript("OnEnter", function(self) 
        self:SetBackdropColor(0.2, 0.2, 0.2, 1) 
        rfIcon:SetVertexColor(1, 1, 1)
    end)

    refreshBtn:SetScript("OnLeave", function(self) 
        self:SetBackdropColor(0.15, 0.15, 0.18, 1) 
        rfIcon:SetVertexColor(0, 0.8, 1.0) 
    end)

    local close = CreateFrame("Button", nil, f, "BackdropTemplate")
    close:SetSize(24, 24); close:SetPoint("TOPRIGHT", -10, -10)
    close:SetBackdrop({bgFile = "Interface\\Buttons\\WHITE8X8"})
    close:SetBackdropColor(0.6, 0.2, 0.2, 0.8)
    local closeText = close:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    closeText:SetText("X"); closeText:SetPoint("CENTER", 0, 0); closeText:SetTextColor(1, 1, 1)
    close:SetScript("OnClick", function() f:Hide() end)

    local count = toolbar:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    count:SetPoint("RIGHT", -10, 0); count:SetTextColor(0, 0.8, 1.0)
    self.ResultCount = count

    -- 3. CONTENT PANELS
    local leftScroll = CreateFrame("ScrollFrame", nil, f, "UIPanelScrollFrameTemplate")
    leftScroll:SetPoint("TOPLEFT", 5, -50); leftScroll:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", -5, 5)
    leftScroll:SetWidth(SIDEBAR_WIDTH); leftScroll.ScrollBar:Hide(); leftScroll.ScrollBar:SetAlpha(0)
    self.LeftScroll = leftScroll

    local leftContent = CreateFrame("Frame", nil, leftScroll)
    leftContent:SetSize(SIDEBAR_WIDTH - 2, 1); leftScroll:SetScrollChild(leftContent)
    self.LeftContent = leftContent

    local rightScroll = CreateFrame("ScrollFrame", "WDIGIRightScroll", f, "UIPanelScrollFrameTemplate")
    rightScroll:SetPoint("TOPLEFT", f, "TOPLEFT", SIDEBAR_WIDTH + 5, -50)
    rightScroll:SetPoint("BOTTOMRIGHT", -5, 5) 
    self.RightScrollFrame = rightScroll
    rightScroll.ScrollBar:Hide(); rightScroll.ScrollBar:SetAlpha(0)

    local rightContent = CreateFrame("Frame", nil, rightScroll)
    rightContent:SetSize(f:GetWidth() - SIDEBAR_WIDTH - 15, 1)
    rightScroll:SetScrollChild(rightContent)
    self.RightContent = rightContent

    -- 4. EXPERIMENTAL SPLASH SCREEN
    local sf = CreateFrame("Frame", nil, f)
    sf:SetPoint("TOPLEFT", SIDEBAR_WIDTH + 15, -60)
    sf:SetPoint("BOTTOMRIGHT", -15, 15)
    
    local st = sf:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    st:SetPoint("TOPLEFT", -10, 0); st:SetText("Compendium |cffff0000(Experimental)|r")
    
    local sd = sf:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    sd:SetPoint("TOPLEFT", st, "BOTTOMLEFT", 0, -20); sd:SetJustifyH("LEFT")
    sd:SetText("This feature is currently in active development.\n\n" ..
            "|cff00ccffHow to use:|r\n" ..
            "1. Enter an Item or NPC name in the search box.\n" ..
            "2. Wait for the list to populate (requires 3+ characters).\n" ..
            "3. Select a result to view sources and costs.\n\n" ..
            "|cffffcc00Data Note:|r\n" ..
            "We are still refning out data, so likely there are inaccurate or missing items.\n\n" ..
            "|cffffcc00Performance Note:|r\n" ..
            "- Searching uses a coroutine-based engine to prevent game stuttering.\n" ..
            "- Large result sets are capped for speed.\n\n" .. 
            "Find this addon useful? Buy me a coffee!\n"  .. 
            "|cff00ccffhttps://buymeacoffee.com/slashzero|r")
    
    self.SplashFrame = sf
end

function WDIGI.Compendium:PerformSearch(query)
    query = query:trim():lower()
    if #query < 3 then return end
    if self.LastQuery == query then return end

    if self.SplashFrame then self.SplashFrame:Hide() end

    self.LastQuery = query
    
    if self.SearchThread then self.SearchThread = nil end

    self.ListRows = self.ListRows or {}
    self.DetailRows = self.DetailRows or {}

    for _, row in ipairs(self.ListRows) do if row then row:Hide() end end
    for _, row in ipairs(self.DetailRows) do if row then row:Hide() end end
    
    self.LeftScroll:SetVerticalScroll(0)
    self.RightScrollFrame:SetVerticalScroll(0)

    self.SearchThread = coroutine.create(function()
        -- 1. Call our high-speed UniversalSearch
        local searchResult = WDIGI.Data.UniversalSearch(query)
        
        local itemResults = searchResult.items or {}
        local vendorResults = {}

        -- 1. FORCE WIDE LAYOUT FOR RESULTS
        WDIGI.Compendium:SetDetailLayout(false)
        
        -- 2. BRIDGE: Map the 'creatures' found in search to the sidebar format
        -- results.creatures contains the vendor names (strings)
        if searchResult.creatures then
            for _, vendorName in ipairs(searchResult.creatures) do
                -- Compendium expects a table with a 'name' field
                table.insert(vendorResults, { name = vendorName })
            end
        end

        -- 3. RENDER: This puts Vendors on top, Items below
        WDIGI.Compendium:RenderList(itemResults, vendorResults)

        -- 4. AUTO-SELECT: If the search matches an item exactly, show it
        if #itemResults > 0 then
            local itemName = GetItemInfo(itemResults[1])
            if itemName and itemName:lower() == query then
                WDIGI.Compendium:SetDetailLayout(true)
                WDIGI.Compendium:RenderItemDetails(itemResults[1])
            end
        end
    end)

    local ticker
    ticker = C_Timer.NewTicker(0.01, function()
        if not self.SearchThread or coroutine.status(self.SearchThread) == "dead" then
            ticker:Cancel()
        else
            local success, err = coroutine.resume(self.SearchThread)
            if not success then
                print("|cffff0000WDIGI Search Error:|r", err)
                ticker:Cancel()
            end
        end
    end)
end

------------------------------------------------------------
-- RENDER LISTS
------------------------------------------------------------

function WDIGI.Compendium:SetDetailLayout(showDetail)
    if not self.Frame then return end
    if showDetail then
        -- Split View (Detail Mode)
        self.RightScrollFrame:Show()
        self.LeftScroll:SetWidth(SIDEBAR_WIDTH)
        self.LeftContent:SetWidth(SIDEBAR_WIDTH - 2)
    else
        -- Wide View (Search Mode)
        self.RightScrollFrame:Hide()
        self.LeftScroll:SetWidth(self.Frame:GetWidth() - 10)
        self.LeftContent:SetWidth(self.Frame:GetWidth() - 25)
    end
end

function WDIGI.Compendium:RenderList(items, vendors)
    local offset, count = 0, 0
    local currentWidth = self.LeftContent:GetWidth()
    local isWide = not self.RightScrollFrame:IsShown() -- Check if we are in wide mode

    for _, v in ipairs(vendors) do
        count = count + 1
        local row = self:GetOrCreateListRow(count)
        self:StyleListRow(row, "LIST")
        row:SetWidth(currentWidth)
        
        -- Fix Alignment for Wide Mode
        if isWide then
            row.name:SetJustifyH("CENTER")
            row.name:ClearAllPoints()
            row.name:SetPoint("CENTER", row, "CENTER", 0, 0)
        else
            row.name:SetJustifyH("LEFT")
            row.name:ClearAllPoints()
            row.name:SetPoint("LEFT", 34, 0)
        end

        row.id = v.name; row.mode = "VENDOR"
        row.name:SetText("|cff00ff00" .. v.name .. "|r")
        row.icon:SetTexture(ENTITY_ICONS.NPC)
        row:SetPoint("TOPLEFT", self.LeftContent, "TOPLEFT", 0, -offset)
        row:Show(); offset = offset + 34
    end

    for _, itemID in ipairs(items) do
        count = count + 1; if count > 30 then break end
        local row = self:GetOrCreateListRow(count)
        self:StyleListRow(row, "LIST")
        row:SetWidth(currentWidth)
        
        -- Fix Alignment for Wide Mode
        if isWide then
            row.name:SetJustifyH("CENTER")
            row.name:ClearAllPoints()
            row.name:SetPoint("CENTER", row, "CENTER", 0, 0)
        else
            row.name:SetJustifyH("LEFT")
            row.name:ClearAllPoints()
            row.name:SetPoint("LEFT", 34, 0)
        end

        row.id = itemID; row.mode = "ITEM"
        local itemName, _, _, _, _, _, _, _, _, itemTexture = GetItemInfo(itemID)
        row.name:SetText(itemName or "Loading...")
        row.icon:SetTexture(itemTexture or 134400)
        row:SetPoint("TOPLEFT", self.LeftContent, "TOPLEFT", 0, -offset)
        row:Show(); offset = offset + 34
    end
    self.LeftContent:SetHeight(offset)
end

------------------------------------------------------------
-- DETAIL RENDERING
------------------------------------------------------------
function WDIGI.Compendium:RenderVendorDetails(vendorName)
    self:SetDetailLayout(true)
    if not vendorName then return end

    if self.SplashFrame then self.SplashFrame:Hide() end
    for _, row in ipairs(self.DetailRows) do row:Hide() end
    for _, row in ipairs(self.ListRows) do row:Hide() end
    
    local inventory = VENDOR_INDEX_LIST[vendorName] or {}
    local leftOffset = 0
    local rightOffset, rightCount = 0, 0 -- CLUTCH: Define these once at the top

    -- 1. FEATURED NPC CARD (Left Sidebar)
    local feat = self:GetOrCreateListRow(100)
    self:StyleListRow(feat, "FEATURED")
    feat.name:SetText("|cff00ff00" .. vendorName .. "|r")
    feat.icon:SetTexture(135911) 
    feat.icon:SetTexCoord(0.2, 0.8, 0.15, 0.85)
    
    -- 2. PEEK AT NPC DATA
    local mapID, tx, ty, vType = 0, 0, 0, 99
    if inventory[1] then
        local firstItemData = WDIGI.Data.ParseItemData(inventory[1])
        for _, s in ipairs(firstItemData) do
            if s.vendorName:lower() == vendorName:lower() then 
                mapID, tx, ty, vType = s.mapID, s.tx, s.ty, s.vendorType
                break 
            end
        end
    end

    -- Update Sidebar Meta Text
    local mapInfo = C_Map.GetMapInfo(mapID)
    local zoneName = mapInfo and mapInfo.name or "Unknown Zone"
    feat.meta:SetText(string.format("|cffffffff%s|r\n%0.1f, %0.1f\n\nInventory: %d Items", zoneName, tx, ty, #inventory))
    feat:SetPoint("TOPLEFT", self.LeftContent, "TOPLEFT", 0, 0)
    feat:Show(); leftOffset = 180

    -- 3. DYNAMIC HEADER (Right Pane)
    --local actionText = (WDIGI.Data.VENDOR_TYPE_NAMES[vType] or "Source"):upper()
    rightCount = rightCount + 1
    local header = self:GetOrCreateDetailRow(rightCount, "ZONE")
    --header.name:SetText(actionText .. ": " .. vendorName:upper())
    header.name:SetText(vendorName:upper())
    header:SetPoint("TOPLEFT", self.RightContent, "TOPLEFT", 0, 0)
    header:Show(); rightOffset = 30

    -- 4. THE NAVIGATION ROW
    if tx > 0 then
        rightCount = rightCount + 1
        local locRow = self:GetOrCreateDetailRow(rightCount, "VENDOR")
        locRow.name:SetText("|cff00ff00[GO TO LOCATION]|r - " .. zoneName)
        locRow.price:SetText("") 
        locRow.coords:SetText(string.format("%.1f, %.1f", tx, ty))
        locRow.icon:SetTexture(135911)
        locRow.pin:Show()
        
        -- Bind the data so clicking it triggers the Nav HUD
        locRow.data = { mapID = mapID, tx = tx, ty = ty, vendorName = vendorName, vendorType = vType }
        locRow.itemID = 0 
        
        locRow:SetPoint("TOPLEFT", self.RightContent, "TOPLEFT", 0, -rightOffset)
        locRow:Show(); rightOffset = rightOffset + 38
    end

    -- 5. INVENTORY SUB-HEADER
    local invHeaderText = (vType == 1) and "ITEMS SOLD" or "KNOWN DROPS"
    rightCount = rightCount + 1
    local invHeader = self:GetOrCreateDetailRow(rightCount, "SUBTYPE")
    invHeader.name:SetText(invHeaderText)
    invHeader:SetPoint("TOPLEFT", self.RightContent, "TOPLEFT", 0, -rightOffset)
    invHeader:Show(); rightOffset = rightOffset + 24

    -- 6. INVENTORY LIST
    local rowWidth = self.Frame:GetWidth() - SIDEBAR_WIDTH - 15
    for _, itemID in ipairs(inventory) do
        rightCount = rightCount + 1
        local row = self:GetOrCreateDetailRow(rightCount, "VENDOR")
        row:SetSize(rowWidth, 32)
        
        local itemName, itemLink, _, _, _, _, _, _, _, itemTexture = GetItemInfo(itemID)
        row.itemID = itemID
        row.icon:SetTexture(itemTexture or 134400)
        row.icon:SetTexCoord(0, 1, 0, 1) 
        row.name:SetText(itemLink or itemName or "Loading...")
        
        local displayCost, coordsText = "", ""
        local itemData = WDIGI.Data.ParseItemData(itemID) 
        for _, source in ipairs(itemData) do
            if tostring(source.vendorName or ""):lower() == vendorName:lower() then
                displayCost = source.cost or ""
                if source.vendorType == 2 then -- Drop %
                    if not displayCost:find("%%") then displayCost = displayCost .. "%" end
                elseif not displayCost:find("%%") then -- Money
                    displayCost = WDIGI.Data.FormatMoney(displayCost)
                end
                if source.tx and source.tx > 0 then coordsText = string.format("%.1f, %.1f", source.tx, source.ty) end
                break 
            end
        end
        -- Update Content
        row.price:SetText(displayCost)
        
        -- HIDE AND SHIFT LOGIC
        row.coords:SetText("")
        row.pin:Hide()
        
        -- Clear existing anchors and snap to the right edge of the row
        row.price:ClearAllPoints()
        row.price:SetPoint("RIGHT", row, "RIGHT", -10, 0)
        row.price:SetJustifyH("RIGHT")

        row:SetPoint("TOPLEFT", self.RightContent, "TOPLEFT", 0, -rightOffset)
        row:Show()
        rightOffset = rightOffset + 34
    end

    self.LeftContent:SetHeight(leftOffset + 20)
    self.RightContent:SetHeight(rightOffset)
end

function WDIGI.Compendium:RenderItemDetails(itemID)
    self:SetDetailLayout(true)
    if self.SplashFrame then self.SplashFrame:Hide() end
    for _, row in ipairs(self.ListRows) do row:Hide() end
    for _, row in ipairs(self.DetailRows) do row:Hide() end
    
    local itemName, itemLink, _, _, _, _, _, _, _, itemTexture = GetItemInfo(itemID)
    if itemName then self.SearchBox:SetText(itemName) end
    
    local rawEntries = WDIGI.Data.ParseItemData(itemID)
    local leftOffset = 0
    
    local feat = self:GetOrCreateListRow(100)
    self:StyleListRow(feat, "FEATURED")
    feat.name:SetText(itemLink or itemName or ITEM_NAMES_LIST[itemID] or "Loading...")
    feat.icon:SetTexture(itemTexture or 134400)
    
    local locations, maps, drops, vendors = 0, {}, 0, 0
    for _, e in ipairs(rawEntries) do
        locations = locations + 1
        maps[e.mapID] = true
        if e.vendorType == VT.DROPPED_BY then drops = drops + 1 end
        if e.vendorType == VT.SOLD_BY then vendors = vendors + 1 end
    end
    local mapCount = 0; for _ in pairs(maps) do mapCount = mapCount + 1 end
    
    feat.meta:SetText(string.format("Total Sources: %d\nMap Areas: %d\nTotal Drops: %d\nTotal Vendors: %d", locations, mapCount, drops, vendors))
    feat:SetPoint("TOPLEFT", self.LeftContent, "TOPLEFT", 0, 0)
    feat:Show(); leftOffset = 180

    local best = WDIGI.Data.GetBestLocation(itemID)
    if best and best.zoneID and best.zoneID > 0 then
        local btn = self:GetOrCreateListRow(101)
        self:StyleListRow(btn, "ACTION")
        btn.name:SetText("TARGET NEAREST")
        btn:SetScript("OnClick", function()
            WDIGI.Navigation.SetPin(best.zoneID, best.x, best.y, best.vendorName, itemName, best.cost, "NEAREST SOURCE", itemTexture)
        end)
        btn:Show(); leftOffset = leftOffset + 45
    end

    local rightOffset, rightCount = 0, 0
    rightCount = rightCount + 1
    local relHeader = self:GetOrCreateDetailRow(rightCount, "ZONE")
    relHeader.name:SetText("ALL KNOWN SOURCES (SORTED BY CLOSEST)")
    relHeader:SetPoint("TOPLEFT", self.RightContent, "TOPLEFT", 0, 0)
    relHeader:Show(); rightOffset = 30

    local myMapID, px, py = WDIGI.MapUtils.GetCurrentPlayerData()
    local processed = {}
    
    for _, e in ipairs(rawEntries) do
        local matchLevel = WDIGI.MapUtils.GetZoneMatchLevel(myMapID, e.mapID)
        local dist = 999999 -- Default to nearly infinite

        -- 🌟 THE SPATIAL PROTECTION GATES (Compendium Match):
        -- ONLY calculate physical distance if we are on the EXACT same map layer (matchLevel == 0).
        -- If it's a subzone or parent relationship (1) or completely foreign (2+), assign a heavy penalty.
        if matchLevel == 0 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
            local mult = WDIGI.MapUtils.GetZoneMultiplier(e.mapID) or 1000
            dist = math.sqrt(dx * dx + dy * dy) * mult
        else
            -- Scale the penalty based on how far away the zone tier is
            dist = 1000000 * (matchLevel + 1)
        end

        local mapInfo = C_Map.GetMapInfo(e.mapID)
        table.insert(processed, { 
            entry = e, 
            matchLevel = matchLevel, 
            dist = dist, 
            zoneName = mapInfo and mapInfo.name or "Unknown Location" 
        })
    end

    table.sort(processed, function(a, b)
        if a.matchLevel ~= b.matchLevel then return a.matchLevel < b.matchLevel end
        if a.entry.vendorType ~= b.entry.vendorType then return a.entry.vendorType < b.entry.vendorType end
        return a.dist < b.dist
    end)

    local lastZone, lastType = "", -1
    for _, data in ipairs(processed) do
        local e = data.entry
        if data.zoneName ~= lastZone then
            rightCount = rightCount + 1; local zRow = self:GetOrCreateDetailRow(rightCount, "ZONE")
            zRow.name:SetText(data.zoneName:upper()); zRow:SetPoint("TOPLEFT", self.RightContent, "TOPLEFT", 0, -rightOffset)
            zRow:Show(); rightOffset = rightOffset + 26; lastZone, lastType = data.zoneName, -1
        end
        if e.vendorType ~= lastType then
            rightCount = rightCount + 1; local tRow = self:GetOrCreateDetailRow(rightCount, "SUBTYPE")
            tRow.name:SetText((WDIGI.Data.VENDOR_TYPE_NAMES[e.vendorType] or "Source"):upper())
            tRow:SetPoint("TOPLEFT", self.RightContent, "TOPLEFT", 0, -rightOffset)
            tRow:Show(); rightOffset = rightOffset + 20; lastType = e.vendorType
        end
        rightCount = rightCount + 1; local row = self:GetOrCreateDetailRow(rightCount, "VENDOR")
        row.data, row.itemID, row.itemIcon = e, itemID, itemTexture

        -- 🏷️ NEW: Dynamic Price/Drop Color Gradient Logic
        local displayCost = e.cost or ""
        
        if displayCost ~= "" then
            -- 🎯 Check if it's a drop (e.vendorType == 2 is WDIGI.Data.VENDOR_TYPE.DROPPED_BY)
            if e.vendorType == 2 then
                local percentNum = 0
                
                if displayCost == "0" then
                    displayCost = "<0.1%"
                    percentNum = 0.05 -- Weight uncalculated/ultra-rare near zero
                else
                    -- Strip pre-existing '%' signs for pure mathematical interpolation
                    local sanitizedCost = displayCost:gsub("%%", "")
                    percentNum = tonumber(sanitizedCost) or 0
                    
                    if not displayCost:find("%%") then
                        displayCost = displayCost .. "%"
                    end
                end

                -- 🎨 GLOWING AMETHYST VARIANT COLOR SLIDE:
                local factor = math.max(0, math.min(100, percentNum)) / 100
                
                -- 0% (Ultra Rare)   = Glowing Electric Violet  (207, 122, 255)
                -- 100% (Guaranteed) = Crisp Ice Diamond Blue   (0, 218, 255)
                local r_col = math.floor(207 - (207 * factor))
                local g_col = math.floor(122 + (96 * factor))
                local b_col = 255 -- Maxed out for absolute dark-UI readability

                local colorTag = string.format("|cff%02x%02x%02x", r_col, g_col, b_col)
                displayCost = colorTag .. displayCost .. "|r"
            
            -- 💰 It's a standard gold store vendor price
            elseif displayCost ~= "0" and not displayCost:find("%%") then
                -- Formats raw copper string to golden text string via your data engine
                local formattedGold = WDIGI.Data.FormatMoney(displayCost)
                local colorTag = "|cffffd100" -- Blizzard Classic Vendor Gold Hex
                displayCost = colorTag .. formattedGold .. "|r"
            else
                displayCost = "" -- Clear out artifacts
            end
        end

        -- FIXED ICON LOGIC: Use rich sourceType data
        if e.sourceType == "creature" or (e.npcID and e.npcID > 0) then
            row.icon:SetTexture(135911)
            row.icon:SetTexCoord(0.15, 0.85, 0.15, 0.85)
        elseif e.sourceType == "gameobject" then
            row.icon:SetTexture(132594)
            row.icon:SetTexCoord(0, 1, 0, 1)
        else
            row.icon:SetTexture(WDIGI.Data.VENDOR_ICONS[e.vendorType] or 134400)
            row.icon:SetTexCoord(0, 1, 0, 1) 
        end

        -- UPDATED NAME: Append the Era Badge if available
        --local eraTag = (e.clientVer and e.clientVer ~= "") and (" |cff808080["..e.clientVer.."]|r") or ""
        --row.name:SetText(e.vendorName .. eraTag)
        row.name:SetText(e.vendorName)
        
        row.price:SetText(displayCost or "")
        row.coords:SetText(e.tx > 0 and string.format("%.1f, %.1f", e.tx, e.ty) or "")
        row.pin:SetShown(e.tx > 0)
        
        row:SetPoint("TOPLEFT", self.RightContent, "TOPLEFT", 0, -rightOffset)
        row:Show()
        rightOffset = rightOffset + 34
    end

    self.LeftContent:SetHeight(leftOffset + 200); self.RightContent:SetHeight(rightOffset)
end

------------------------------------------------------------
-- FACTORIES & STYLING
------------------------------------------------------------
function WDIGI.Compendium:GetOrCreateListRow(index)
    -- 1. Recycle existing row if available
    if self.ListRows[index] then return self.ListRows[index] end

    -- 2. Create the base Button frame
    local row = CreateFrame("Button", nil, self.LeftContent, "BackdropTemplate")
    row:SetSize(SIDEBAR_WIDTH - 5, 32)
    row:SetBackdrop({bgFile = "Interface\\Buttons\\WHITE8X8"})
    
    -- 3. Icon (Texture)
    row.icon = row:CreateTexture(nil, "ARTWORK")
    row.icon:SetSize(22, 22)
    row.icon:SetPoint("LEFT", 6, 0)
    
    -- 4. Main Name String
    row.name = row:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    row.name:SetPoint("LEFT", 34, 0)
    row.name:SetPoint("RIGHT", -4, 0)
    row.name:SetJustifyH("LEFT")
    row.name:SetWordWrap(false)
    
    -- 5. Meta Info String (Hidden by default, used for "FEATURED" mode)
    row.meta = row:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    row.meta:SetPoint("TOP", row.name, "BOTTOM", 0, -10)
    row.meta:Hide()
    
    -- 6. Click Handler
    row:SetScript("OnClick", function(s) 
        if s.mode == "VENDOR" then 
            -- s.id here should be the vendorName string
            self:RenderVendorDetails(s.id) 
        else 
            -- s.id here is the itemID integer
            self:RenderItemDetails(s.id) 
        end 
    end)
    
    table.insert(self.ListRows, row)
    return row
end

function WDIGI.Compendium:StyleListRow(row, type)
    row:SetBackdrop({bgFile = "Interface\\Buttons\\WHITE8X8"})
    row:SetBackdropColor(0, 0, 0, 0); row:SetBackdropBorderColor(0, 0, 0, 0)
    row.icon:Show(); row.icon:ClearAllPoints(); row.icon:SetTexCoord(0, 1, 0, 1) 
    row.name:ClearAllPoints(); row.name:SetFontObject("GameFontNormalSmall"); row.meta:Hide()
    row:SetScript("OnClick", function(s) if s.mode == "VENDOR" then self:RenderVendorDetails(s.id) else self:RenderItemDetails(s.id) end end)

    if type == "FEATURED" then
        row:SetSize(SIDEBAR_WIDTH - 10, 170)
        row:SetBackdropColor(unpack(COLORS.CARD_BG))
        row.icon:SetSize(64, 64); row.icon:SetPoint("TOP", 0, -15)
        row.name:SetPoint("TOP", row.icon, "BOTTOM", 0, -10); row.name:SetPoint("LEFT", 5, 0); row.name:SetPoint("RIGHT", -5, 0)
        row.name:SetJustifyH("CENTER"); row.name:SetFontObject("GameFontNormalLarge")
        row.meta:Show(); row.meta:SetJustifyH("CENTER"); row.meta:SetTextColor(unpack(COLORS.TEXT_DIM))
        row:SetScript("OnClick", nil)
    elseif type == "ACTION" then
        row:SetSize(SIDEBAR_WIDTH - 30, 30); row:SetBackdrop({bgFile = "Interface\\Buttons\\WHITE8X8", edgeFile = "Interface\\Buttons\\WHITE8X8", edgeSize = 1})
        row:SetBackdropColor(0.1, 0.4, 0.1, 0.9); row:SetBackdropBorderColor(0.2, 0.6, 0.2, 1)
        row.icon:Hide(); row.name:SetPoint("LEFT", 0, 0); row.name:SetPoint("RIGHT", 0, 0); row.name:SetJustifyH("CENTER")
    elseif type == "LIST" then
        row:SetSize(SIDEBAR_WIDTH - 5, 32); row.icon:SetSize(22, 22); row.icon:SetPoint("LEFT", 6, 0)
        row.name:SetPoint("LEFT", 34, 0); row.name:SetPoint("RIGHT", -4, 0); row:SetBackdropColor(0.15, 0.15, 0.15, 0.5)
    end
end

function WDIGI.Compendium:GetOrCreateDetailRow(index, type)
    -- Check for an existing row in the pool to recycle
    if self.DetailRows[index] then 
        local r = self.DetailRows[index]
        r:Hide()
        self:StyleDetailRow(r, type)
        return r 
    end

    -- Create new row if pool is empty
    local row = CreateFrame("Button", nil, self.RightContent, "BackdropTemplate")
    row.icon = row:CreateTexture(nil, "ARTWORK")
    row.name = row:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    row.price = row:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    row.coords = row:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    row.coords:SetTextColor(unpack(COLORS.AMBER_TEXT))
    
    -- The UI Pin/Map Icon
    row.pin = row:CreateTexture(nil, "OVERLAY")
    row.pin:SetTexture("Interface\\Minimap\\POIIcons")
    row.pin:SetTexCoord(0.4, 0.45, 0.4, 0.45)
    row.pin:SetSize(16, 16)

    -- THE CLICK HANDLER: Standardized for Normalized Data
    row:SetScript("OnClick", function(s) 
        if s.data then 
            local e = s.data
            WDIGI.Navigation.SetPin(
                e.mapID, 
                e.tx, 
                e.ty, 
                e.vendorName, 
                GetItemInfo(s.itemID) or "Item", 
                e.cost,       -- Passed as raw value for HUD formatting
                WDIGI.Data.VENDOR_TYPE_NAMES[e.vendorType], 
                s.itemIcon, 
                WDIGI.Data.VENDOR_ICONS[e.vendorType],
                e.npcID,      -- New rich ID
                e.sourceType  -- New rich type string
            ) 
        end 
    end)

    self:StyleDetailRow(row, type)
    table.insert(self.DetailRows, row)
    
    return row
end

function WDIGI.Compendium:StyleDetailRow(row, type)
    local availableWidth = self.Frame:GetWidth() - SIDEBAR_WIDTH - 15
    row:SetBackdrop({bgFile = "Interface\\Buttons\\WHITE8X8"})
    row.icon:Hide(); row.price:Hide(); row.pin:Hide(); row.coords:Hide()
    row.icon:SetTexCoord(0, 1, 0, 1) 
    
    if type == "ZONE" then
        row:SetSize(availableWidth, 24)
        row:SetBackdropColor(unpack(COLORS.BG_HDR_ZONE))
        row.name:ClearAllPoints(); row.name:SetPoint("LEFT", 10, 0); row.name:SetFontObject("GameFontNormalSmall")
    elseif type == "SUBTYPE" then
        row:SetSize(availableWidth, 18)
        row:SetBackdropColor(unpack(COLORS.BG_HDR_SUBTYPE)) 
        row.name:ClearAllPoints(); row.name:SetPoint("LEFT", 10, 0); row.name:SetFontObject("GameFontHighlightSmall"); row.name:SetTextColor(unpack(COLORS.AMBER_TEXT))
    else 
        row:SetSize(availableWidth, 32)
        row:SetBackdropColor(0, 0, 0, 0.2)
        row.icon:Show(); row.icon:SetSize(26, 26); row.icon:SetPoint("LEFT", 10, 0)
        row.name:ClearAllPoints(); row.name:SetPoint("LEFT", 44, 0)
        row.price:Show(); row.price:SetPoint("RIGHT", -110, 0)
        row.coords:Show(); row.coords:SetPoint("RIGHT", -32, 0)
        row.pin:Show(); row.pin:SetPoint("RIGHT", -10, 0)
    end
end

function WDIGI.Compendium:Toggle()
    if not WDIGI.Settings.Get("WDIGI_EnableCompendium_Experimental") then return end
    if not self.Frame then self:Create(); self.Frame:Show() else
        if self.Frame:IsShown() then self.Frame:Hide() else self.Frame:Show(); if self.SearchBox then self.SearchBox:SetFocus() end end
    end
end

local eventFrame = CreateFrame("Frame")
eventFrame:RegisterEvent("ADDON_LOADED")
eventFrame:RegisterEvent("GET_ITEM_INFO_RECEIVED")
eventFrame:SetScript("OnEvent", function(f, event, arg1)
    if event == "ADDON_LOADED" and arg1 == "WhereDoIGetIt" then WDIGI.Compendium:CreateMinimapButton()
    elseif event == "GET_ITEM_INFO_RECEIVED" then
        if WDIGI.Compendium.Frame and WDIGI.Compendium.Frame:IsShown() then
            local currentSearch = WDIGI.Compendium.SearchBox:GetText()
            if #currentSearch >= 3 and currentSearch:lower() ~= (WDIGI.Compendium.LastQuery or "") then WDIGI.Compendium:PerformSearch(currentSearch) end
        end
    end
end)