-- Enhanced Raid Browser — MainFrame v5
-- Shows top 7 items per slot per phase with rank numbers
local ADDON_NAME, NS = ...
local ERB = NS.ERB
local ETB = NS.ETB

local MF = {}
ERB.MainFrame = MF

MF.frame = nil
MF.itemRows = {}
MF.slotButtons = {}
MF.phaseTabs = {}
MF.detailLines = {}

-- ============================================================================
-- CONSTANTS
-- ============================================================================

local FRAME_WIDTH = 1100
local FRAME_HEIGHT = 750
local SIDEBAR_WIDTH = 170
local DETAIL_WIDTH = 300
local FRAME_MARGIN = 15
local TITLE_HEIGHT = 45
local TOPBAR_HEIGHT = 50
local BOTTOMBAR_HEIGHT = 10
local CONTENT_Y = -(TITLE_HEIGHT + TOPBAR_HEIGHT + 5)
local BOTTOM_MARGIN = FRAME_MARGIN + BOTTOMBAR_HEIGHT + 5
local ITEM_ROW_HEIGHT = 36
local MAX_ITEMS = 7

local SLOT_ICONS = {
    Head="Interface\\PaperDoll\\UI-PaperDoll-Slot-Head",
    Neck="Interface\\PaperDoll\\UI-PaperDoll-Slot-Neck",
    Shoulder="Interface\\PaperDoll\\UI-PaperDoll-Slot-Shoulder",
    Back="Interface\\PaperDoll\\UI-PaperDoll-Slot-Chest",
    Chest="Interface\\PaperDoll\\UI-PaperDoll-Slot-Chest",
    Wrist="Interface\\PaperDoll\\UI-PaperDoll-Slot-Wrists",
    Hands="Interface\\PaperDoll\\UI-PaperDoll-Slot-Hands",
    Waist="Interface\\PaperDoll\\UI-PaperDoll-Slot-Waist",
    Legs="Interface\\PaperDoll\\UI-PaperDoll-Slot-Legs",
    Feet="Interface\\PaperDoll\\UI-PaperDoll-Slot-Feet",
    Finger="Interface\\PaperDoll\\UI-PaperDoll-Slot-Finger",
    Trinket="Interface\\PaperDoll\\UI-PaperDoll-Slot-Trinket",
    ["Main Hand"]="Interface\\PaperDoll\\UI-PaperDoll-Slot-MainHand",
    ["Off Hand"]="Interface\\PaperDoll\\UI-PaperDoll-Slot-SecondaryHand",
    ["Two Hand"]="Interface\\PaperDoll\\UI-PaperDoll-Slot-MainHand",
    Ranged="Interface\\PaperDoll\\UI-PaperDoll-Slot-Ranged",
    Weapon="Interface\\PaperDoll\\UI-PaperDoll-Slot-MainHand",
}

local RANK_COLORS = {
    [1] = "|cffff8000",  -- orange BiS
    [2] = "|cffa335ee",  -- purple
    [3] = "|cff0070dd",  -- blue
    [4] = "|cff1eff00",  -- green
    [5] = "|cff888888",  -- gray
    [6] = "|cff888888",  -- gray
    [7] = "|cff888888",  -- gray
}

-- ============================================================================
-- ITEM OWNERSHIP
-- ============================================================================

local function PlayerOwnsItem(itemID)
    for slot = 1, 18 do
        if GetInventoryItemID("player", slot) == itemID then return true end
    end
    for bag = 0, NUM_BAG_SLOTS do
        for slot = 1, C_Container.GetContainerNumSlots(bag) do
            if C_Container.GetContainerItemID(bag, slot) == itemID then return true end
        end
    end
    return false
end

-- ============================================================================
-- CREATE MAIN FRAME
-- ============================================================================

function MF:Create()
    if self.frame then return self.frame end

    local f = CreateFrame("Frame", nil, UIParent, "BackdropTemplate")
    f:SetSize(FRAME_WIDTH, FRAME_HEIGHT)
    f:SetPoint("CENTER")
    f:SetBackdrop({
        bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background-Dark",
        edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Border",
        tile = true, tileSize = 32, edgeSize = 32,
        insets = { left = 8, right = 8, top = 8, bottom = 8 }
    })
    f:SetBackdropColor(0, 0, 0, 1)  -- Fully opaque black
    f:SetMovable(true)
    f:EnableMouse(true)
    f:RegisterForDrag("LeftButton")
    f:SetScript("OnDragStart", f.StartMoving)
    f:SetScript("OnDragStop", f.StopMovingOrSizing)
    f:SetFrameStrata("HIGH")
    f:SetFrameLevel(50)
    
    -- Solid blocker to ensure nothing bleeds through
    local blocker = f:CreateTexture(nil, "BACKGROUND", nil, -8)
    blocker:SetAllPoints(f)
    blocker:SetColorTexture(0.02, 0.02, 0.03, 1)
    
    f:Hide()

    f:SetScript("OnKeyDown", function(self, key)
        if key == "ESCAPE" then
            pcall(self.SetPropagateKeyboardInput, self, false)
            self:Hide()
        else
            pcall(self.SetPropagateKeyboardInput, self, true)
        end
    end)

    f.closeBtn = CreateFrame("Button", nil, f, "UIPanelCloseButton")
    f.closeBtn:SetPoint("TOPRIGHT", -8, -8)

    -- Toggle button: switch to ETB Transmog Browser
    f.transmogToggle = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
    f.transmogToggle:SetSize(80, 22)
    f.transmogToggle:SetPoint("TOPRIGHT", -38, -16)
    f.transmogToggle:SetText("Transmog")
    f.transmogToggle:SetScript("OnClick", function()
        if ETB and ETB.ToggleUIMode then ETB:ToggleUIMode() end
    end)
    f.transmogToggle:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_BOTTOM")
        GameTooltip:AddLine("Switch to Transmog Browser")
        GameTooltip:Show()
    end)
    f.transmogToggle:SetScript("OnLeave", function() GameTooltip:Hide() end)

    f.title = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    f.title:SetPoint("TOP", 0, -18)
    f.title:SetText("|cffffd100Enhanced Raid Browser|r")

    f.version = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    f.version:SetPoint("TOPRIGHT", -40, -22)
    f.version:SetText("|cff888888v" .. (ERB.version or "0.1") .. "|r")

    self:CreateTopBar(f)
    self:CreateLeftSidebar(f)
    self:CreateItemGrid(f)
    self:CreateDetailPanel(f)

    self.frame = f
    
    -- Handle async item info loads
    local eventFrame = CreateFrame("Frame")
    f._refreshPending = false
    f._refreshCount = 0
    
    f:SetScript("OnShow", function()
        f._refreshCount = 0
        f._refreshPending = false
        eventFrame:RegisterEvent("GET_ITEM_INFO_RECEIVED")
    end)
    f:SetScript("OnHide", function()
        eventFrame:UnregisterAllEvents()
        f._refreshPending = false
    end)
    
    eventFrame:SetScript("OnEvent", function(_, event, itemID)
        if not f:IsShown() then return end
        if f._refreshCount >= 4 then
            eventFrame:UnregisterAllEvents()
            return
        end
        if not f._refreshPending then
            f._refreshPending = true
            C_Timer.After(0.3, function()
                f._refreshPending = false
                f._refreshCount = f._refreshCount + 1
                if f:IsShown() then
                    MF:UpdateDisplay()
                end
            end)
        end
    end)
    
    return f
end

-- ============================================================================
-- TOP BAR — Spec, source toggle, phase tabs
-- ============================================================================

function MF:CreateTopBar(f)
    local bar = CreateFrame("Frame", nil, f, "BackdropTemplate")
    bar:SetPoint("TOPLEFT", FRAME_MARGIN, -TITLE_HEIGHT)
    bar:SetPoint("TOPRIGHT", -FRAME_MARGIN, -TITLE_HEIGHT)
    bar:SetHeight(TOPBAR_HEIGHT)
    bar:SetBackdrop({
        bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        tile = true, tileSize = 16, edgeSize = 12,
        insets = { left = 4, right = 4, top = 4, bottom = 4 }
    })
    f.topBar = bar

    f.specLabel = bar:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    f.specLabel:SetPoint("TOPLEFT", 10, -6)

    -- Spec selector buttons (created dynamically in UpdateSpecButtons)
    f.specButtonContainer = CreateFrame("Frame", nil, bar)
    f.specButtonContainer:SetPoint("LEFT", f.specLabel, "RIGHT", 12, 0)
    f.specButtonContainer:SetSize(400, 22)

    -- Item count (top right)
    f.itemCountLabel = bar:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    f.itemCountLabel:SetPoint("TOPRIGHT", -10, -8)

    -- Source toggle button (bottom right of top bar)
    -- Source label (WoWTBC only, no toggle needed)
    f.sourceLabel = bar:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    f.sourceLabel:SetPoint("BOTTOMRIGHT", -10, 10)
    f.sourceLabel:SetText("|cff00ccffWoWTBC|r")

    -- Phase tabs
    f.phaseContainer = CreateFrame("Frame", nil, bar)
    f.phaseContainer:SetPoint("BOTTOMLEFT", 8, 6)
    f.phaseContainer:SetSize(FRAME_WIDTH - 160, 22)
end

-- ============================================================================
-- LEFT SIDEBAR — Slot buttons
-- ============================================================================

function MF:CreateLeftSidebar(f)
    local sidebar = CreateFrame("Frame", nil, f, "BackdropTemplate")
    sidebar:SetWidth(SIDEBAR_WIDTH)
    sidebar:SetPoint("TOPLEFT", FRAME_MARGIN, CONTENT_Y)
    sidebar:SetPoint("BOTTOMLEFT", FRAME_MARGIN, BOTTOM_MARGIN)
    sidebar:SetBackdrop({
        bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        tile = true, tileSize = 16, edgeSize = 12,
        insets = { left = 4, right = 4, top = 4, bottom = 4 }
    })
    sidebar:SetClipsChildren(true)
    f.sidebar = sidebar

    local title = sidebar:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    title:SetPoint("TOP", 0, -8)
    title:SetText("|cff00ffffGear Slots|r")

    local divider = sidebar:CreateTexture(nil, "ARTWORK")
    divider:SetSize(SIDEBAR_WIDTH - 16, 2)
    divider:SetPoint("TOP", 0, -28)
    divider:SetColorTexture(0.5, 0.5, 0.5, 0.5)

    self.slotButtons = {}
    local yOff = -36
    for _, slot in ipairs(ERB.DataBridge and ERB.DataBridge.SLOT_ORDER or {
        "Head","Neck","Shoulder","Back","Chest","Wrist",
        "Hands","Waist","Legs","Feet","Finger","Trinket",
        "Main Hand","Off Hand","Two Hand","Ranged","Weapon"
    }) do
        local btn = CreateFrame("Button", nil, sidebar)
        btn:SetSize(SIDEBAR_WIDTH - 12, 28)
        btn:SetPoint("TOPLEFT", 6, yOff)

        local bg = btn:CreateTexture(nil, "BACKGROUND")
        bg:SetAllPoints()
        bg:SetColorTexture(0, 0, 0, 0)
        btn.bg = bg

        local icon = btn:CreateTexture(nil, "ARTWORK")
        icon:SetSize(22, 22)
        icon:SetPoint("LEFT", 4, 0)
        icon:SetTexture(SLOT_ICONS[slot] or "Interface\\Icons\\INV_Misc_QuestionMark")
        icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)

        local text = btn:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        text:SetPoint("LEFT", icon, "RIGHT", 6, 0)
        text:SetText(slot)
        btn.label = text

        local countText = btn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        countText:SetPoint("RIGHT", -6, 0)
        btn.countLabel = countText

        btn.selected = btn:CreateTexture(nil, "OVERLAY")
        btn.selected:SetAllPoints()
        btn.selected:SetColorTexture(0, 0.5, 1, 0.3)
        btn.selected:Hide()

        btn:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square", "ADD")
        btn.slotName = slot
        btn:SetScript("OnClick", function() MF:SelectSlot(slot) end)

        self.slotButtons[slot] = btn
        yOff = yOff - 29
    end
end

-- ============================================================================
-- ITEM GRID — shows items for selected slot, ranked with #1 - #6
-- ============================================================================

function MF:CreateItemGrid(f)
    local grid = CreateFrame("Frame", nil, f, "BackdropTemplate")
    grid:SetPoint("TOPLEFT", f.sidebar, "TOPRIGHT", 8, 0)
    grid:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -(DETAIL_WIDTH + FRAME_MARGIN + 8), BOTTOM_MARGIN)
    grid:SetBackdrop({
        bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background-Dark",
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        tile = true, tileSize = 16, edgeSize = 12,
        insets = { left = 4, right = 4, top = 4, bottom = 4 }
    })
    grid:SetBackdropColor(0, 0, 0, 1)
    f.gridFrame = grid

    f.gridLabel = grid:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    f.gridLabel:SetPoint("TOPLEFT", 8, -8)

    -- EQUIPPED SECTION
    f.equippedLabel = grid:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    f.equippedLabel:SetPoint("TOPLEFT", 8, -26)
    f.equippedLabel:SetText("|cffffd100Currently Equipped:|r")

    -- Equipped item rows (up to 2 for dual slots like Finger/Trinket)
    self.equippedRows = {}
    for i = 1, 2 do
        local eRow = self:CreateItemRow(grid, 0)
        -- Positions set dynamically in UpdateDisplay
        eRow:SetPoint("TOPLEFT", 8, -40 - (i-1) * ITEM_ROW_HEIGHT)
        eRow:SetPoint("RIGHT", grid, "RIGHT", -8, 0)
        eRow:Hide()
        self.equippedRows[i] = eRow
    end

    -- Divider between equipped and BiS (positioned dynamically)
    f.equippedDivider = grid:CreateTexture(nil, "ARTWORK")
    f.equippedDivider:SetSize(10, 2)
    f.equippedDivider:SetPoint("TOPLEFT", 8, -78)
    f.equippedDivider:SetPoint("RIGHT", grid, "RIGHT", -8, 0)
    f.equippedDivider:SetColorTexture(0.4, 0.4, 0.4, 0.5)

    f.bisLabel = grid:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    f.bisLabel:SetPoint("TOPLEFT", 8, -84)
    f.bisLabel:SetText("|cffffd100BiS Rankings:|r")

    -- BiS item rows (positioned dynamically in UpdateDisplay)
    self.itemRows = {}
    for i = 1, MAX_ITEMS do
        local row = self:CreateItemRow(grid, i)
        row:SetPoint("TOPLEFT", 8, -100 - (i-1) * ITEM_ROW_HEIGHT)
        row:SetPoint("RIGHT", grid, "RIGHT", -8, 0)
        row:Hide()
        self.itemRows[i] = row
    end

    -- "No items" label
    f.noItemsLabel = grid:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    f.noItemsLabel:SetPoint("CENTER", 0, 20)
    f.noItemsLabel:SetText("|cff888888No items for this slot in current phase|r")
    f.noItemsLabel:Hide()

    -- Item count
    f.slotCountLabel = grid:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    f.slotCountLabel:SetPoint("TOPRIGHT", -8, -8)
end

-- ============================================================================
-- ITEM ROW — individual ranked item
-- ============================================================================

function MF:CreateItemRow(parent, index)
    local row = CreateFrame("Button", nil, parent)
    row:SetHeight(ITEM_ROW_HEIGHT)

    local bg = row:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints()
    bg:SetColorTexture(0.1, 0.1, 0.12, 0.5)
    row.bg = bg
    row:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square", "ADD")

    -- Rank number (#1, #2, etc.)
    local rankNum = row:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    rankNum:SetPoint("LEFT", 6, 0)
    rankNum:SetWidth(28)
    rankNum:SetJustifyH("CENTER")
    row.rankNum = rankNum

    -- Item icon
    local icon = row:CreateTexture(nil, "ARTWORK")
    icon:SetSize(ITEM_ROW_HEIGHT - 6, ITEM_ROW_HEIGHT - 6)
    icon:SetPoint("LEFT", 36, 0)
    icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
    row.icon = icon

    -- Item name (top line)
    local nameText = row:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    nameText:SetPoint("TOPLEFT", icon, "TOPRIGHT", 8, -2)
    nameText:SetPoint("RIGHT", row, "RIGHT", -80, 0)
    nameText:SetJustifyH("LEFT")
    nameText:SetWordWrap(false)
    row.nameText = nameText

    -- Source line (bottom)
    local subText = row:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    subText:SetPoint("BOTTOMLEFT", icon, "BOTTOMRIGHT", 8, 2)
    subText:SetPoint("RIGHT", row, "RIGHT", -80, 0)
    subText:SetJustifyH("LEFT")
    subText:SetWordWrap(false)
    row.subText = subText

    -- Rank label (right side, top)
    local rankLabel = row:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    rankLabel:SetPoint("TOPRIGHT", -6, -4)
    rankLabel:SetJustifyH("RIGHT")
    row.rankLabel = rankLabel

    -- Status (right side, bottom)
    local statusText = row:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    statusText:SetPoint("BOTTOMRIGHT", -6, 4)
    statusText:SetJustifyH("RIGHT")
    row.statusText = statusText

    -- Tooltip + detail panel on hover
    row:SetScript("OnEnter", function(self)
        if self.itemID then
            GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
            GameTooltip:SetItemByID(self.itemID)
            GameTooltip:Show()
            MF:ShowItemDetail(self.itemID, self._itemData)
        end
    end)
    row:SetScript("OnLeave", function() GameTooltip:Hide() end)

    return row
end

-- ============================================================================
-- DETAIL PANEL (right side)
-- ============================================================================

function MF:CreateDetailPanel(f)
    local panel = CreateFrame("Frame", nil, f, "BackdropTemplate")
    panel:SetWidth(DETAIL_WIDTH)
    panel:SetPoint("TOPRIGHT", -FRAME_MARGIN, CONTENT_Y)
    panel:SetPoint("BOTTOMRIGHT", -FRAME_MARGIN, BOTTOM_MARGIN)
    panel:SetBackdrop({
        bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        tile = true, tileSize = 16, edgeSize = 12,
        insets = { left = 4, right = 4, top = 4, bottom = 4 }
    })
    f.detailPanel = panel

    local title = panel:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    title:SetPoint("TOP", 0, -8)
    title:SetText("|cff00ffffItem Details|r")

    local divider = panel:CreateTexture(nil, "ARTWORK")
    divider:SetSize(DETAIL_WIDTH - 16, 2)
    divider:SetPoint("TOP", 0, -28)
    divider:SetColorTexture(0.5, 0.5, 0.5, 0.5)

    local scrollParent = CreateFrame("Frame", nil, panel)
    scrollParent:SetPoint("TOPLEFT", 6, -34)
    scrollParent:SetPoint("BOTTOMRIGHT", -24, 6)
    local scroll = CreateFrame("ScrollFrame", nil, scrollParent, "UIPanelScrollFrameTemplate")
    scroll:SetAllPoints()
    local content = CreateFrame("Frame", nil, scroll)
    content:SetWidth(DETAIL_WIDTH - 40)
    content:SetHeight(1)
    scroll:SetScrollChild(content)
    f.detailContent = content
    self.detailLines = {}
end

-- ============================================================================
-- SLOT SELECTION
-- ============================================================================

function MF:SelectSlot(slot)
    if not ERB.DataBridge then return end
    ERB.DataBridge.currentSlot = slot

    for s, btn in pairs(self.slotButtons) do
        if s == slot then
            btn.selected:Show()
            btn.label:SetText("|cff00ff00" .. s .. "|r")
        else
            btn.selected:Hide()
            btn.label:SetText(s)
        end
    end

    -- Pre-cache all items for this slot so names resolve before display
    local phase = ERB.DataBridge:GetCurrentPhase()
    local items = ERB.DataBridge:GetItemsForSlot(slot, phase)
    local uncached = 0
    for _, item in ipairs(items) do
        local name = GetItemInfo(item.itemID)
        if not name then uncached = uncached + 1 end
    end

    -- Reset refresh counter so event-driven refreshes work for this slot
    if self.frame then
        self.frame._refreshCount = 0
        self.frame._refreshPending = false
    end

    self:UpdateDisplay()
    
    -- If any items were uncached, schedule refreshes as they load
    if uncached > 0 then
        C_Timer.After(0.4, function()
            if self.frame and self.frame:IsShown() then
                self:UpdateDisplay()
            end
        end)
        C_Timer.After(1.0, function()
            if self.frame and self.frame:IsShown() then
                self:UpdateDisplay()
            end
        end)
    end
end

-- ============================================================================
-- SPEC SELECTOR BUTTONS
-- ============================================================================

MF.specButtons = {}

function MF:UpdateSpecButtons()
    -- Clear old buttons
    for _, btn in ipairs(self.specButtons) do btn:Hide() end
    self.specButtons = {}

    if not ERB.DataBridge then return end
    local specs = ERB.DataBridge:GetAvailableSpecs()
    if #specs <= 1 then return end  -- no point showing selector for single-spec

    local container = self.frame.specButtonContainer
    local xOff = 0

    for _, spec in ipairs(specs) do
        local btn = CreateFrame("Button", nil, container)
        btn:SetSize(math.max(70, #spec.name * 7 + 16), 20)
        btn:SetPoint("LEFT", xOff, 0)

        local bg = btn:CreateTexture(nil, "BACKGROUND")
        bg:SetAllPoints()
        if spec.isActive then
            bg:SetColorTexture(0.2, 0.5, 0.2, 0.8)
        else
            bg:SetColorTexture(0.15, 0.15, 0.15, 0.5)
        end
        btn.bg = bg

        local txt = btn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        txt:SetPoint("CENTER")
        if spec.isActive then
            txt:SetText("|cffffffff" .. spec.name .. "|r")
        else
            txt:SetText("|cff888888" .. spec.name .. "|r")
        end

        btn:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square", "ADD")

        local specIdx = spec.idx
        btn:SetScript("OnClick", function()
            if ERB.DataBridge:SwitchSpec(specIdx) then
                ERB.equipped = ERB:ScanEquipment()
                MF:Refresh()
                MF:SelectSlot(ERB.DataBridge.currentSlot or "Head")
            end
        end)

        btn:SetScript("OnEnter", function(self)
            GameTooltip:SetOwner(self, "ANCHOR_BOTTOM")
            GameTooltip:AddLine(spec.name)
            if spec.isActive then
                GameTooltip:AddLine("|cff00ff00Currently viewing|r", 1, 1, 1)
            else
                GameTooltip:AddLine("Click to view BiS for this spec", 1, 1, 1)
            end
            GameTooltip:Show()
        end)
        btn:SetScript("OnLeave", function() GameTooltip:Hide() end)

        self.specButtons[#self.specButtons + 1] = btn
        xOff = xOff + btn:GetWidth() + 4
    end
end

-- ============================================================================
-- UPDATE PHASE TABS
-- ============================================================================

function MF:UpdatePhaseTabs()
    for _, tab in ipairs(self.phaseTabs) do tab:Hide() end
    self.phaseTabs = {}
    if not ERB.DataBridge then return end

    local phases = ERB.DataBridge:GetPhases()
    local container = self.frame.phaseContainer
    local xOff = 0

    for _, phase in ipairs(phases) do
        local name = ERB.DataBridge:GetPhaseName(phase)
        local active = (phase == ERB.DataBridge:GetCurrentPhase())

        local tab = CreateFrame("Button", nil, container)
        tab:SetSize(math.max(80, #name * 7 + 24), 20)
        tab:SetPoint("LEFT", xOff, 0)

        local bg = tab:CreateTexture(nil, "BACKGROUND")
        bg:SetAllPoints()
        bg:SetColorTexture(active and 0.2 or 0.1, active and 0.4 or 0.1, active and 0.7 or 0.1, active and 0.9 or 0.4)
        tab.bg = bg

        local txt = tab:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        txt:SetPoint("CENTER")
        txt:SetText(active and ("|cffffffff" .. name .. "|r") or ("|cff888888" .. name .. "|r"))

        tab:SetScript("OnClick", function()
            ERB.DataBridge:SetPhase(phase)
            MF:Refresh()
            MF:SelectSlot(ERB.DataBridge.currentSlot or "Head")
        end)
        tab:SetScript("OnEnter", function(s) if not active then s.bg:SetColorTexture(0.2, 0.2, 0.3, 0.6) end end)
        tab:SetScript("OnLeave", function(s) if not active then s.bg:SetColorTexture(0.1, 0.1, 0.1, 0.4) end end)

        self.phaseTabs[#self.phaseTabs+1] = tab
        xOff = xOff + tab:GetWidth() + 4
    end
end

-- ============================================================================
-- UPDATE SIDEBAR COUNTS
-- ============================================================================

function MF:UpdateSlotCounts()
    if not ERB.DataBridge then return end
    local counts = ERB.DataBridge:GetAllSlotCounts()
    for slot, btn in pairs(self.slotButtons) do
        local count = counts[slot] or 0
        btn.countLabel:SetText(count > 0 and ("|cff888888" .. count .. "|r") or "")
    end
end

-- ============================================================================
-- UPDATE DISPLAY — ranked items for current slot
-- ============================================================================

function MF:UpdateDisplay()
    if not self.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 "?"

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

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

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

        for i, eq in ipairs(equipped) do
            if i > 2 then break end
            local eRow = self.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
        self.frame.equippedLabel:SetText("|cffffd100Currently Equipped:|r |cff888888(empty)|r")
        self.frame.equippedLabel:Show()
    end

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

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

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

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

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

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

    if #rawItems == 0 then
        self.frame.noItemsLabel:Show()
        self.frame.slotCountLabel:SetText("")
        return
    end
    self.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)
            itemName = "item_" .. item.itemID  -- temp unique key
        end
        
        -- Strip common suffixes for matching
        local baseName = itemName
        
        if not seenNames[baseName] then
            seenNames[baseName] = #displayItems + 1
            local entry = {
                itemID = item.itemID,
                rank = #displayItems + 1,
                label = (#displayItems == 0) and "BiS" or ("Alt " .. (#displayItems + 1)),
                spec = item.spec,
                isCurrent = item.isCurrent,
                isUpgraded = item.isUpgraded,
                variants = {},
            }
            -- If this is TF, 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
            local existing = displayItems[seenNames[baseName]]
            existing.variants[#existing.variants + 1] = item.itemID
            if item.isUpgraded and not existing.tfItemID then
                existing.tfItemID = item.itemID
            elseif not item.isUpgraded and existing.isUpgraded then
                -- Base version found after TF: swap so base is primary display
                existing.variants[#existing.variants] = existing.itemID
                existing.itemID = item.itemID
                existing.isUpgraded = false
            end
        end
    end

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

    for i = 1, showing do
        local item = displayItems[i]
        local row = self.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 = PlayerOwnsItem(item.itemID)
        -- Also check if any variant is owned
        if not owned and item.tfItemID then
            owned = PlayerOwnsItem(item.tfItemID)
        end
        for _, vid in ipairs(item.variants) do
            if not owned then owned = PlayerOwnsItem(vid) end
        end

        -- Rank number with color
        local rc = 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 isRaidDrop = ETB and ETB.JLoot and ETB.JLoot[item.itemID]
            if isRaidDrop then
                tfTag = " |cff666666(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 MF:ShowItemDetail(itemID, itemData)
    if not self.frame or not self.frame.detailContent then return end
    local content = self.frame.detailContent

    for _, line in ipairs(self.detailLines) do line:Hide() end
    self.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 = self:AddDetailLine(content, yOff, qc .. itemName .. "|r", "GameFontNormal")
    end

    yOff = yOff + 4

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

        if itemData.spec then
            local detailInfo = ERB:GetPlayerInfo()
            local dc = detailInfo.classColor or "|cffffffff"
            yOff = self: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 = self:AddDetailLine(content, yOff, "|cff448899Thunderforged:|r " .. tfName)
            else
                yOff = self:AddDetailLine(content, yOff, "|cff448899Thunderforged version available|r")
            end
        else
            local isRaidDrop = ETB and ETB.JLoot and ETB.JLoot[itemID]
            if isRaidDrop then
                yOff = yOff + 2
                yOff = self:AddDetailLine(content, yOff, "|cff666666Upgradeable to Thunderforged ilvl|r")
            end
        end
    end

    yOff = yOff + 6

    -- Boss / drop source
    local bossName = ERB.DataBridge:GetBossName(itemID)
    if bossName and bossName ~= "" then
        yOff = self:AddDetailLine(content, yOff, "|cffffd100Drops from:|r")
        yOff = self: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 = self:AddDetailLine(content, yOff, "|cff66bbffCrafted: " .. prof .. skillStr .. "|r")

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

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

    content:SetHeight(yOff + 10)
end

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

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

function MF:Refresh()
    if not self.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)
    self.frame.specLabel:SetText(
        specIcon .. classColor .. (info.name or "?") .. "|r " ..
        classColor .. (info.className or "?") .. "|r"
    )
    
    self.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
    
    self:UpdateSpecButtons()
    self:UpdatePhaseTabs()
    self:UpdateSlotCounts()
    self:UpdateDisplay()
    
    -- If items were uncached, schedule refreshes as they load
    if uncached > 0 then
        C_Timer.After(0.5, function()
            if self.frame and self.frame:IsShown() then
                self:UpdateDisplay()
            end
        end)
        C_Timer.After(1.5, function()
            if self.frame and self.frame:IsShown() then
                self:UpdateDisplay()
            end
        end)
    end
end

-- ============================================================================
-- TOGGLE
-- ============================================================================

function MF:Toggle()
    if not self.frame then self:Create() end
    if self.frame:IsShown() then
        self.frame:Hide()
    else
        self:Refresh()
        self:SelectSlot(ERB.DataBridge and ERB.DataBridge.currentSlot or "Head")
        self.frame:Show()
    end
end

function MF:IsShown()
    return self.frame and self.frame:IsShown()
end
