--[[
============================================================================
ERB/UI/MainFrame/Display.lua  (added in v15.3.0 — Audit Batch 4 Part 3)
============================================================================

Data-rendering logic for the ERB MainFrame orchestrator. Owner-pattern:
each method takes `owner` (the MF orchestrator) as first argument.

Methods owned here (4):
  UpdateDisplay      — primary render path (~215 lines). Reads the
                       BiSData store for the current slot+spec+phase,
                       sorts/filters by score, populates the visible
                       item rows up to MAX_ITEMS.
  ShowItemDetail     — populate the right-hand detail panel for a
                       selected item (ownership, sources, drop rates)
  AddDetailLine      — helper that adds one FontString to the detail
                       panel and tracks it in owner.detailLines
  Refresh            — entry point invoked from outside (e.g. when the
                       user re-opens the frame). Clears the row cache
                       and dispatches to UpdateDisplay + UpdateSpecButtons.

External dependencies pulled from owner (the MF orchestrator):
  owner.frame, owner.detailLines, owner.itemRows, owner.specButtons
  owner.currentSlot, owner.currentSpec, owner.currentSource (Tier toggle)
  owner.PlayerOwnsItem (function) — accessed as owner.PlayerOwnsItem(itemID),
    not as a method. Originally a file-local function in MainFrame.lua,
    exposed on MF in v15.3.0 pre-extraction.
  owner.MAX_ITEMS, owner.ITEM_ROW_HEIGHT, owner.DETAIL_WIDTH, owner.RANK_COLORS
  owner:UpdateSpecButtons, owner:UpdatePhaseTabs, owner:UpdateSlotCounts,
  owner:UpdateDisplay, owner:ShowItemDetail, owner:AddDetailLine — internal
    cross-method calls
  ERB.DataBridge — namespace-level data source (BiSData lookup)
  ERB.BiSData — namespace-level item data

Closure / shadowing notes: zero closures, all synchronous rendering.
============================================================================
]]--
local ADDON_NAME, NS = ...
local ETB = NS.ETB
local ERB = ETB and ETB.ERB
if not ERB then return end

NS.ETB.ERB.MainFrame = NS.ETB.ERB.MainFrame or {}
NS.ETB.ERB.MainFrame.Display = NS.ETB.ERB.MainFrame.Display or {}
local Display = NS.ETB.ERB.MainFrame.Display

-- =============================================================================
-- METHODS (extracted from ERB/UI/MainFrame.lua in v15.3.0)
-- =============================================================================

function Display:UpdateDisplay(owner)
    if not owner.frame or not ERB.DataBridge then return end

    local slot = ERB.DataBridge.currentSlot or "Head"
    local phase = ERB.DataBridge:GetCurrentPhase()
    local phaseName = ERB.DataBridge:GetPhaseName(phase) or phase or "?"

    owner.frame.gridLabel:SetText("|cff00ffff" .. slot .. "|r |cffffd100— " .. phaseName .. " BiS|r")

    -- EQUIPPED SECTION — show what's currently in this slot
    for _, eRow in ipairs(owner.equippedRows) do eRow:Hide() end

    local equipped = ERB.equipped and ERB.equipped[slot]
    local equippedCount = 0
    if equipped and #equipped > 0 then
        owner.frame.equippedLabel:Show()

        for i, eq in ipairs(equipped) do
            if i > 2 then break end
            local eRow = owner.equippedRows[i]
            if eRow then
                local qColor = "|cffffffff"
                if eq.quality and eq.quality > 0 then
                    local r, g, b = GetItemQualityColor(eq.quality)
                    qColor = string.format("|cff%02x%02x%02x", r*255, g*255, b*255)
                end
                eRow.rankNum:SetText("|cffffd100E|r")
                eRow.icon:SetTexture(eq.icon or "Interface\\Icons\\INV_Misc_QuestionMark")
                eRow.nameText:SetText(qColor .. (eq.name or "?") .. "|r")
                eRow.subText:SetText("|cff888888ilvl " .. (eq.ilvl or "?") .. "|r")
                eRow.rankLabel:SetText("|cffffd100Equipped|r")
                eRow.statusText:SetText("")
                eRow.bg:SetColorTexture(0.15, 0.12, 0.05, 0.5)
                eRow.itemID = eq.itemID
                eRow._itemData = nil
                eRow:Show()
                equippedCount = i
            end
        end
    else
        owner.frame.equippedLabel:SetText("|cffffd100Currently Equipped:|r |cff888888(empty)|r")
        owner.frame.equippedLabel:Show()
    end

    -- Dynamic positioning: divider, bisLabel, and BiS rows shift based on equipped count
    local dividerY = -40 - equippedCount * owner.ITEM_ROW_HEIGHT - 4
    local bisLabelY = dividerY - 6
    local bisStartY = bisLabelY - 16

    owner.frame.equippedDivider:ClearAllPoints()
    owner.frame.equippedDivider:SetPoint("TOPLEFT", 8, dividerY)
    owner.frame.equippedDivider:SetPoint("RIGHT", owner.frame.gridFrame, "RIGHT", -8, 0)
    owner.frame.equippedDivider:Show()

    owner.frame.bisLabel:ClearAllPoints()
    owner.frame.bisLabel:SetPoint("TOPLEFT", 8, bisLabelY)
    owner.frame.bisLabel:Show()

    -- Reposition all BiS item rows
    for i, row in ipairs(owner.itemRows) do
        row:ClearAllPoints()
        row:SetPoint("TOPLEFT", 8, bisStartY - (i-1) * owner.ITEM_ROW_HEIGHT)
        row:SetPoint("RIGHT", owner.frame.gridFrame, "RIGHT", -8, 0)
    end

    -- BIS ITEMS
    local rawItems = ERB.DataBridge:GetItemsForSlot(slot, phase)

    -- Hide all rows
    for _, row in ipairs(owner.itemRows) do row:Hide() end

    if #rawItems == 0 then
        owner.frame.noItemsLabel:Show()
        owner.frame.slotCountLabel:SetText("")
        return
    end
    owner.frame.noItemsLabel:Hide()

    -- Deduplicate: collapse items with same name into one entry
    -- TF variants (96000-97999) and base items of same name become one row
    local displayItems = {}
    local seenNames = {}
    
    for _, item in ipairs(rawItems) do
        local itemName = GetItemInfo(item.itemID)
        if not itemName then
            GetItemInfo(item.itemID)               -- warm cache; UpdateDisplay re-runs on GET_ITEM_INFO_RECEIVED
            itemName = "item_" .. item.itemID       -- temp unique key (self-heals once the name loads)
        end

        -- Strip common suffixes for matching
        local baseName = itemName
        -- A Thunderforged/Warforged variant shares its base item's name; bucketing
        -- it under the base name collapses the pair into one entry.
        local bisRank = item.rank or 99

        if not seenNames[baseName] then
            seenNames[baseName] = #displayItems + 1
            local entry = {
                itemID = item.itemID,
                bisRank = bisRank,                  -- authoritative rank from the BiS guide (preserved through merge)
                spec = item.spec,
                isCurrent = item.isCurrent,
                isUpgraded = item.isUpgraded,
                variants = {},
            }
            -- If this is the forged variant, note it; base version may come later
            if item.isUpgraded then
                entry.tfItemID = item.itemID
            end
            displayItems[#displayItems + 1] = entry
        else
            -- Same name already exists - attach as variant and keep the BETTER rank
            local existing = displayItems[seenNames[baseName]]
            existing.variants[#existing.variants + 1] = item.itemID
            if bisRank < (existing.bisRank or 99) then existing.bisRank = bisRank end
            if item.isUpgraded and not existing.tfItemID then
                existing.tfItemID = item.itemID
            elseif not item.isUpgraded and existing.isUpgraded then
                -- Base version found after the forged one: make base the primary display
                existing.variants[#existing.variants] = existing.itemID
                existing.itemID = item.itemID
                existing.isUpgraded = false
            end
        end
    end

    -- Order by the BiS guide's rank (best first), then number contiguously so a
    -- collapsed base+forged pair always takes the higher of the two ranks and
    -- nothing below it is bumped down by an un-collapsed duplicate.
    table.sort(displayItems, function(a, b) return (a.bisRank or 99) < (b.bisRank or 99) end)
    for idx, entry in ipairs(displayItems) do
        entry.rank = idx
        entry.label = (idx == 1) and "BiS" or ("Alt " .. idx)
    end

    local showing = math.min(#displayItems, owner.MAX_ITEMS)
    owner.frame.slotCountLabel:SetText("|cff888888" .. #rawItems .. " total (" .. #displayItems .. " unique)|r")

    for i = 1, showing do
        local item = displayItems[i]
        local row = owner.itemRows[i]
        if not row then break end

        -- Try GetItemInfo first (returns full data if cached)
        local itemName, _, quality, _, _, _, subType, _, equipLoc, texture = GetItemInfo(item.itemID)
        if not itemName and GetItemInfoInstant then
            local _, _, _, _, iIcon = GetItemInfoInstant(item.itemID)
            texture = iIcon
            itemName = "Loading..."
            quality = 4
            GetItemInfo(item.itemID)
        elseif not itemName then
            itemName = "Loading..."
            quality = 4
            GetItemInfo(item.itemID)
        end

        local owned = owner.PlayerOwnsItem(item.itemID)
        -- Also check if any variant is owned
        if not owned and item.tfItemID then
            owned = owner.PlayerOwnsItem(item.tfItemID)
        end
        for _, vid in ipairs(item.variants) do
            if not owned then owned = owner.PlayerOwnsItem(vid) end
        end

        -- Rank number with color
        local rc = owner.RANK_COLORS[item.rank] or "|cff888888"
        row.rankNum:SetText(rc .. "#" .. item.rank .. "|r")

        -- Icon
        row.icon:SetTexture(texture or "Interface\\Icons\\INV_Misc_QuestionMark")

        -- Name with quality color + variant info
        local qColor = "|cffffffff"
        if quality and quality > 0 then
            local r, g, b = GetItemQualityColor(quality)
            qColor = string.format("|cff%02x%02x%02x", r*255, g*255, b*255)
        end
        local tfTag = ""
        if item.tfItemID then
            tfTag = " |cff448899(TF)|r"
        else
            local fkind = ETB and ETB.Forge and ETB.Forge:GetForgeKindByItem(item.itemID)
            if fkind then
                local abbr = (fkind == "Warforged") and "WF" or "TF"
                tfTag = " |cff666666(" .. abbr .. " upgradeable)|r"
            end
        end
        row.nameText:SetText(qColor .. itemName .. "|r" .. tfTag)

        -- Sub text: boss name or profession
        local sub = ""
        local profInfo = ERB.DataBridge:GetProfessionInfo(item.itemID)
        if profInfo then
            sub = "|cff66bbff" .. (profInfo.profession or "Crafted")
            if profInfo.skill and profInfo.skill > 0 then
                sub = sub .. " " .. profInfo.skill
            end
            sub = sub .. "|r"
        else
            local bossName = ERB.DataBridge:GetBossName(item.itemID)
            if bossName and bossName ~= "" then
                sub = "|cff888888" .. bossName .. "|r"
            end
        end
        row.subText:SetText(sub)

        -- Rank label
        row.rankLabel:SetText(rc .. (item.label or "?") .. "|r")

        -- Status
        row.statusText:SetText(owned and "|cff00ff00Owned|r" or "|cffff4444Need|r")

        -- Row tint
        if owned then
            row.bg:SetColorTexture(0.05, 0.15, 0.05, 0.4)
        else
            row.bg:SetColorTexture(0.1, 0.1, 0.12, 0.5)
        end

        row.itemID = item.itemID
        row._itemData = item
        row:Show()
    end
end

-- ============================================================================
-- ITEM DETAIL PANEL
-- ============================================================================

function Display:ShowItemDetail(owner, itemID, itemData)
    if not owner.frame or not owner.frame.detailContent then return end
    local content = owner.frame.detailContent

    for _, line in ipairs(owner.detailLines) do line:Hide() end
    owner.detailLines = {}

    local yOff = 0

    -- Item name
    local itemName, _, quality = GetItemInfo(itemID)
    if itemName then
        local qc = "|cffffffff"
        if quality and quality > 0 then
            local r, g, b = GetItemQualityColor(quality)
            qc = string.format("|cff%02x%02x%02x", r*255, g*255, b*255)
        end
        yOff = owner:AddDetailLine(content, yOff, qc .. itemName .. "|r", "GameFontNormal")
    end

    yOff = yOff + 4

    -- Rank + phase
    if itemData then
        local rc = owner.RANK_COLORS[itemData.rank] or "|cff888888"
        local phase = ERB.DataBridge:GetCurrentPhase()
        local phaseName = ERB.DataBridge:GetPhaseName(phase) or "?"
        yOff = owner:AddDetailLine(content, yOff, rc .. "Rank #" .. (itemData.rank or "?") .. "|r — " .. (itemData.label or "?"))
        yOff = owner:AddDetailLine(content, yOff, "|cff888888Phase: " .. phaseName .. "|r")

        if itemData.spec then
            local detailInfo = ERB:GetPlayerInfo()
            local dc = detailInfo.classColor or "|cffffffff"
            yOff = owner:AddDetailLine(content, yOff, "Spec: " .. dc .. (detailInfo.className or "?") .. "|r " .. itemData.spec)
        end
        
        if itemData.tfItemID then
            yOff = yOff + 2
            local tfName = GetItemInfo(itemData.tfItemID)
            if tfName then
                yOff = owner:AddDetailLine(content, yOff, "|cff448899Thunderforged:|r " .. tfName)
            else
                yOff = owner:AddDetailLine(content, yOff, "|cff448899Thunderforged version available|r")
            end
        else
            local fkind = ETB and ETB.Forge and ETB.Forge:GetForgeKindByItem(itemID)
            if fkind then
                yOff = yOff + 2
                yOff = owner:AddDetailLine(content, yOff, "|cff666666Upgradeable to " .. fkind .. " ilvl|r")
            end
        end
    end

    yOff = yOff + 6

    -- Boss / drop source
    local bossName = ERB.DataBridge:GetBossName(itemID)
    if bossName and bossName ~= "" then
        yOff = owner:AddDetailLine(content, yOff, "|cffffd100Drops from:|r")
        yOff = owner:AddDetailLine(content, yOff, "  |cffffffff" .. bossName .. "|r")
    end

    -- Profession + reagents
    local profInfo = ERB.DataBridge:GetProfessionInfo(itemID)
    if profInfo then
        yOff = yOff + 4
        local prof = profInfo.profession or "Crafted"
        local skill = profInfo.skill
        local skillStr = (skill and skill > 0) and (" " .. skill) or ""
        yOff = owner:AddDetailLine(content, yOff, "|cff66bbffCrafted: " .. prof .. skillStr .. "|r")

        local reags = ERB.DataBridge:GetReagents(itemID)
        if reags then
            yOff = owner:AddDetailLine(content, yOff, "|cff888888Reagents:|r")
            for _, entry in ipairs(reags) do
                local reagName = GetItemInfo(entry[1]) or ("Item #" .. entry[1])
                yOff = owner:AddDetailLine(content, yOff, "  |cffffffff" .. reagName .. "|r x" .. entry[2])
            end
        end
    end

    -- Owned status
    yOff = yOff + 6
    local owned = owner.PlayerOwnsItem(itemID)
    yOff = owner:AddDetailLine(content, yOff,
        owned and "|cff00ff00You own this item|r" or "|cffff4444You need this item|r")

    content:SetHeight(yOff + 10)
end

function Display:AddDetailLine(owner, parent, yOff, text, font)
    local line = parent:CreateFontString(nil, "OVERLAY", font or "GameFontHighlightSmall")
    line:SetPoint("TOPLEFT", 4, -yOff)
    line:SetWidth(owner.DETAIL_WIDTH - 50)
    line:SetJustifyH("LEFT")
    line:SetText(text)
    owner.detailLines[#owner.detailLines+1] = line
    return yOff + (line:GetStringHeight() or 14) + 2
end

-- ============================================================================
-- REFRESH
-- ============================================================================

function Display:Refresh(owner)
    if not owner.frame or not ERB.DataBridge then return end
    local info = ERB:GetPlayerInfo()
    
    local specIcon = info.specIcon and ("|T" .. info.specIcon .. ":16:16:0:0|t ") or ""
    local classColor = info.classColor or "|cffffffff"
    local avgIlvl = ERB:GetEquippedIlvl()
    
    -- Show character name + class (spec shown via buttons)
    owner.frame.specLabel:SetText(
        specIcon .. classColor .. (info.name or "?") .. "|r " ..
        classColor .. (info.className or "?") .. "|r"
    )
    
    owner.frame.itemCountLabel:SetText(
        "|cff888888ilvl " .. avgIlvl .. " | " .. ERB.DataBridge:GetBiSCount() .. " BiS items|r"
    )
    
    ERB.equipped = ERB:ScanEquipment()
    
    -- Pre-cache ALL items across all slots and phases
    -- This triggers GetItemInfo for every BiS item so names resolve
    local uncached = 0
    for slotName, phases in pairs(ERB.DataBridge.slotData or {}) do
        for phase, items in pairs(phases) do
            for _, item in ipairs(items) do
                local name = GetItemInfo(item.itemID)
                if not name then uncached = uncached + 1 end
            end
        end
    end
    
    owner:UpdateSpecButtons()
    owner:UpdatePhaseTabs()
    owner:UpdateSlotCounts()
    owner:UpdateDisplay()
    
    -- If items were uncached, schedule refreshes as they load
    if uncached > 0 then
        C_Timer.After(0.5, function()
            if owner.frame and owner.frame:IsShown() then
                owner:UpdateDisplay()
            end
        end)
        C_Timer.After(1.5, function()
            if owner.frame and owner.frame:IsShown() then
                owner:UpdateDisplay()
            end
        end)
    end
end

