local _, ns = ...
local B, C, L, DB = unpack(ns)
local M = B:GetModule("Misc")

local format, strfind, tonumber, pairs, ipairs, strmatch = string.format, string.find, tonumber, pairs, ipairs, string.match
local tinsert, tremove, wipe = table.insert, table.remove, table.wipe
local C_Item_GetItemInfo = C_Item.GetItemInfo
local C_Item_GetItemInfoInstant = C_Item.GetItemInfoInstant
local C_TooltipInfo_GetHyperlink = C_TooltipInfo.GetHyperlink
local C_TooltipInfo_GetItemByID = C_TooltipInfo.GetItemByID
local IsShiftKeyDown = IsShiftKeyDown
local IsControlKeyDown = IsControlKeyDown

local frame

local scanTooltip = CreateFrame("GameTooltip", "OrzUIItemInspectorScanTooltip", nil, "GameTooltipTemplate")
scanTooltip:SetOwner(UIParent, "ANCHOR_NONE")
scanTooltip:Hide()

local DUNGEON_CHEST_IDS = {
    ["魔导师平台"] = 268466,
    ["迈萨拉洞窟"] = 268473,
    ["节点希纳斯"] = 268467,
    ["风行者之塔"] = 268471,
    ["艾杰斯亚学院"] = 268465,
    ["萨隆矿坑"] = 268468,
    ["执政团之座"] = 268469,
    ["通天峰"] = 268470,
}

local RAID_CHEST_IDS = {
    ["弗拉希乌斯"] = 268460,
    ["陨落之王萨哈达尔"] = 268461,
    ["威厄高尔和艾佐拉克"] = 268462,
    ["光盲先锋军"] = 268463,
    ["奇美鲁斯，未梦之神"] = 268464,
}

local DELVE_CHEST_IDS = {
    ["地下堡"] = 268969,
}

local HUNT_CHEST_IDS = {
    ["狩猎"] = 269768,
}

local chestContentsCache = {}

local ALL_CHEST_IDS = {}
for name, id in pairs(DUNGEON_CHEST_IDS) do
    ALL_CHEST_IDS[id] = name
end
for name, id in pairs(RAID_CHEST_IDS) do
    ALL_CHEST_IDS[id] = name
end
for name, id in pairs(DELVE_CHEST_IDS) do
    ALL_CHEST_IDS[id] = name
end
for name, id in pairs(HUNT_CHEST_IDS) do
    ALL_CHEST_IDS[id] = name
end

local POLL_MAX_ATTEMPTS = 5
local POLL_INTERVAL = 0.5
local pollQueue = {}
local pollTimer = nil
local pollAttempts = {}

local function ParseTooltipDataForChest(tooltipData)
    if not tooltipData or not tooltipData.lines then return nil end

    local contents = {}
    local isVoidChest = false
    local chestName = ""
    local dungeonName = ""
    local itemListStarted = false

    for _, lineInfo in ipairs(tooltipData.lines) do
        local text = ""
        if lineInfo.leftText then
            text = lineInfo.leftText
        end

        if strfind(text, "晦暗虚空宝箱") then
            isVoidChest = true
            chestName = text
            dungeonName = strmatch(text, "：(.+)$") or strmatch(text, ":(.+)$")
        end

        if isVoidChest and (strfind(text, "内含下列物品") or strfind(text, "Contains one of the following")) then
            itemListStarted = true
        elseif isVoidChest and itemListStarted and strfind(text, "^%-") then
            local itemName = text:gsub("^%-%s*", "")
            itemName = itemName:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", "")
            if itemName and itemName ~= "" then
                tinsert(contents, {
                    name = itemName,
                    itemID = nil,
                })
            end
        elseif isVoidChest and itemListStarted and text ~= "" and not strfind(text, "^%-") then
            if strfind(text, "物品ID") or strfind(text, "史诗钥石") or strfind(text, "物品等级") then
                -- continue
            else
                itemListStarted = false
            end
        end
    end

    if isVoidChest then
        return {
            chestName = chestName,
            dungeonName = dungeonName,
            contents = contents,
        }
    end

    return nil
end

local function ParseGameTooltipForChest(itemID, itemLink)
    local scanTooltip = _G["OrzUIItemInspectorScanTooltip"]
    if not scanTooltip then return nil end

    scanTooltip:ClearLines()
    scanTooltip:SetOwner(UIParent, "ANCHOR_NONE")

    if itemLink then
        scanTooltip:SetHyperlink(itemLink)
    else
        scanTooltip:SetItemByID(itemID)
    end

    local numLines = scanTooltip:NumLines()
    local contents = {}
    local isVoidChest = false
    local chestName = ""
    local dungeonName = ""
    local itemListStarted = false

    for i = 1, numLines do
        local line = _G["OrzUIItemInspectorScanTooltipTextLeft" .. i]
        if line then
            local text = line:GetText() or ""

            if strfind(text, "晦暗虚空宝箱") then
                isVoidChest = true
                chestName = text
                dungeonName = strmatch(text, "：(.+)$") or strmatch(text, ":(.+)$")
            end

            if isVoidChest and (strfind(text, "内含下列物品") or strfind(text, "Contains one of the following")) then
                itemListStarted = true
            elseif isVoidChest and itemListStarted and strfind(text, "^%-") then
                local itemName = text:gsub("^%-%s*", "")
                itemName = itemName:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", "")
                if itemName and itemName ~= "" then
                    tinsert(contents, {
                        name = itemName,
                        itemID = nil,
                    })
                end
            elseif isVoidChest and itemListStarted and text ~= "" and not strfind(text, "^%-") then
                if strfind(text, "物品ID") or strfind(text, "史诗钥石") or strfind(text, "物品等级") then
                    -- continue
                else
                    itemListStarted = false
                end
            end
        end
    end

    if isVoidChest then
        return {
            chestName = chestName,
            dungeonName = dungeonName,
            contents = contents,
        }
    end

    return nil
end

local function TryScanChest(itemID)
    local itemName, itemLink = C_Item_GetItemInfo(itemID)
    if not itemLink then
        C_Item.RequestLoadItemDataByID(itemID)
        return nil, "loading"
    end

    local tooltipData = C_TooltipInfo_GetItemByID(itemID)
    if tooltipData then
        local result = ParseTooltipDataForChest(tooltipData)
        if result and #result.contents > 0 then
            result.itemLink = itemLink
            result.chestID = itemID
            return result, "success"
        end
    end

    local result2 = ParseGameTooltipForChest(itemID, itemLink)
    if result2 and #result2.contents > 0 then
        result2.itemLink = itemLink
        result2.chestID = itemID
        return result2, "success"
    end

    if tooltipData then
        local result3 = ParseTooltipDataForChest(tooltipData)
        if result3 then
            result3.itemLink = itemLink
            result3.chestID = itemID
            return result3, "no_contents"
        end
    end

    if result2 then
        result2.itemLink = itemLink
        result2.chestID = itemID
        return result2, "no_contents"
    end

    local knownName = ALL_CHEST_IDS[itemID] or ""
    return {
        chestName = "晦暗虚空宝箱：" .. knownName,
        dungeonName = knownName,
        contents = {},
        itemLink = itemLink,
        chestID = itemID,
    }, "no_tooltip"
end

local function ProcessPollQueue()
    if #pollQueue == 0 then
        pollTimer = nil
        return
    end

    local itemID = pollQueue[1]
    local attempts = pollAttempts[itemID] or 0

    local result, status = TryScanChest(itemID)

    if status == "success" then
        tremove(pollQueue, 1)
        pollAttempts[itemID] = nil
        chestContentsCache[itemID] = result
        if frame and frame:IsShown() then
            M:ItemInspector_UpdateDisplay()
        end
    elseif status == "no_contents" then
        attempts = attempts + 1
        pollAttempts[itemID] = attempts
        if attempts >= POLL_MAX_ATTEMPTS then
            tremove(pollQueue, 1)
            pollAttempts[itemID] = nil
            chestContentsCache[itemID] = result
            if frame and frame:IsShown() then
                M:ItemInspector_UpdateDisplay()
            end
        end
    elseif status == "loading" then
        attempts = attempts + 1
        pollAttempts[itemID] = attempts
        if attempts >= POLL_MAX_ATTEMPTS * 2 then
            tremove(pollQueue, 1)
            pollAttempts[itemID] = nil
            local knownName = ALL_CHEST_IDS[itemID] or ""
            chestContentsCache[itemID] = {
                chestName = "晦暗虚空宝箱：" .. knownName,
                dungeonName = knownName,
                contents = {},
                chestID = itemID,
            }
            if frame and frame:IsShown() then
                M:ItemInspector_UpdateDisplay()
            end
        end
    elseif status == "no_tooltip" then
        attempts = attempts + 1
        pollAttempts[itemID] = attempts
        if attempts >= POLL_MAX_ATTEMPTS then
            tremove(pollQueue, 1)
            pollAttempts[itemID] = nil
            chestContentsCache[itemID] = result
            if frame and frame:IsShown() then
                M:ItemInspector_UpdateDisplay()
            end
        end
    end

    if #pollQueue > 0 then
        pollTimer = C_Timer.NewTimer(POLL_INTERVAL, ProcessPollQueue)
    else
        pollTimer = nil
    end
end

function M:ItemInspector_ForcePollAll()
    if pollTimer then
        pollTimer:Cancel()
        pollTimer = nil
    end
    wipe(pollQueue)
    wipe(pollAttempts)

    local allIDs = {}
    for _, id in pairs(DUNGEON_CHEST_IDS) do
        tinsert(allIDs, id)
    end
    for _, id in pairs(RAID_CHEST_IDS) do
        tinsert(allIDs, id)
    end
    for _, id in pairs(DELVE_CHEST_IDS) do
        tinsert(allIDs, id)
    end
    for _, id in pairs(HUNT_CHEST_IDS) do
        tinsert(allIDs, id)
    end

    for _, itemID in ipairs(allIDs) do
        if chestContentsCache[itemID] and #chestContentsCache[itemID].contents > 0 then
            -- already has content, skip
        else
            chestContentsCache[itemID] = nil
            tinsert(pollQueue, itemID)
            C_Item.RequestLoadItemDataByID(itemID)
        end
    end

    M:ItemInspector_UpdateDisplay()

    if #pollQueue > 0 then
        ProcessPollQueue()
    end
end

local eventFrame = CreateFrame("Frame")
eventFrame:RegisterEvent("GET_ITEM_INFO_RECEIVED")
eventFrame:SetScript("OnEvent", function(self, event, itemID, success)
    if event ~= "GET_ITEM_INFO_RECEIVED" then return end
    itemID = tonumber(itemID)
    if not itemID or not success then return end
    if not ALL_CHEST_IDS[itemID] then return end

    if chestContentsCache[itemID] and #chestContentsCache[itemID].contents > 0 then return end

    local result, status = TryScanChest(itemID)
    if status == "success" then
        chestContentsCache[itemID] = result
        if frame and frame:IsShown() then
            M:ItemInspector_UpdateDisplay()
        end
    end
end)

function M:ItemInspector_GetAllChestData()
    local dungeonData = {}
    local raidData = {}
    local delveData = {}
    local huntData = {}

    for dungeonName, chestID in pairs(DUNGEON_CHEST_IDS) do
        if chestContentsCache[chestID] then
            local data = chestContentsCache[chestID]
            data.dungeonName = data.dungeonName or dungeonName
            data.chestID = chestID
            dungeonData[dungeonName] = data
        else
            dungeonData[dungeonName] = {
                chestName = "晦暗虚空宝箱：" .. dungeonName,
                dungeonName = dungeonName,
                contents = {},
                chestID = chestID,
            }
        end
    end

    for bossName, chestID in pairs(RAID_CHEST_IDS) do
        if chestContentsCache[chestID] then
            local data = chestContentsCache[chestID]
            data.dungeonName = data.dungeonName or bossName
            data.chestID = chestID
            raidData[bossName] = data
        else
            raidData[bossName] = {
                chestName = "晦暗虚空宝箱：" .. bossName,
                dungeonName = bossName,
                contents = {},
                chestID = chestID,
            }
        end
    end

    for delveName, chestID in pairs(DELVE_CHEST_IDS) do
        if chestContentsCache[chestID] then
            local data = chestContentsCache[chestID]
            data.dungeonName = data.dungeonName or delveName
            data.chestID = chestID
            delveData[delveName] = data
        else
            delveData[delveName] = {
                chestName = "晦暗虚空宝箱：" .. delveName,
                dungeonName = delveName,
                contents = {},
                chestID = chestID,
            }
        end
    end

    for huntName, chestID in pairs(HUNT_CHEST_IDS) do
        if chestContentsCache[chestID] then
            local data = chestContentsCache[chestID]
            data.dungeonName = data.dungeonName or huntName
            data.chestID = chestID
            huntData[huntName] = data
        else
            huntData[huntName] = {
                chestName = "晦暗虚空宝箱：" .. huntName,
                dungeonName = huntName,
                contents = {},
                chestID = chestID,
            }
        end
    end

    return dungeonData, raidData, delveData, huntData
end

function M:ItemInspector_CreateFrame()
    if frame then return frame end

    frame = CreateFrame("Frame", "OrzUIVoidChestInspector", UIParent, "BackdropTemplate")
    frame:SetSize(700, 700)
    frame:SetPoint("CENTER")
    frame:SetFrameStrata("HIGH")
    frame:SetFrameLevel(100)
    frame:SetMovable(true)
    frame:EnableMouse(true)
    frame:RegisterForDrag("LeftButton")
    frame:SetScript("OnDragStart", frame.StartMoving)
    frame:SetScript("OnDragStop", frame.StopMovingOrSizing)
    B.SetBD(frame)

    frame.title = B.CreateFS(frame, 18, "晦暗虚空宝箱查看器", "system", "TOP", 0, -12)
    frame.subtitle = B.CreateFS(frame, 12, "至暗之夜第1赛季", false, "TOP", 0, -32)
    frame.subtitle:SetTextColor(0.7, 0.7, 0.7)

    frame.close = CreateFrame("Button", nil, frame, "UIPanelCloseButton")
    frame.close:SetPoint("TOPRIGHT", -5, -5)
    B.ReskinClose(frame.close)

    frame.refreshBtn = B.CreateButton(frame, 80, 24, "强制刷新")
    frame.refreshBtn:SetPoint("TOPRIGHT", frame.close, "TOPLEFT", -10, -2)
    frame.refreshBtn:SetScript("OnClick", function()
        wipe(chestContentsCache)
        M:ItemInspector_ForcePollAll()
    end)

    frame.hintText = B.CreateFS(frame, 11, "轮询加载中...", false, "TOP", 0, -50)
    frame.hintText:SetTextColor(0.5, 0.5, 0.5)

    frame.tabBar = CreateFrame("Frame", nil, frame, "BackdropTemplate")
    frame.tabBar:SetPoint("TOPLEFT", 10, -70)
    frame.tabBar:SetPoint("BOTTOMLEFT", 10, 15)
    frame.tabBar:SetWidth(100)
    B.CreateBD(frame.tabBar, .2)

    frame.tabs = {}
    frame.activeTab = "dungeon"

    local function CreateTab(id, text, yOffset)
        local tab = CreateFrame("Button", nil, frame.tabBar, "BackdropTemplate")
        tab:SetSize(90, 30)
        tab:SetPoint("TOP", frame.tabBar, "TOP", 0, yOffset)
        tab.id = id
        B.CreateBD(tab, .3)

        tab.text = B.CreateFS(tab, 12, text, true, "CENTER", 0, 0)
        tab.text:SetTextColor(0.7, 0.7, 0.7)

        tab:SetScript("OnClick", function()
            M:ItemInspector_SwitchTab(id)
        end)

        tab:SetScript("OnEnter", function()
            if frame.activeTab ~= id then
                B.CreateBD(tab, .5)
            end
        end)

        tab:SetScript("OnLeave", function()
            if frame.activeTab ~= id then
                B.CreateBD(tab, .3)
            end
        end)

        return tab
    end

    frame.tabs.dungeon = CreateTab("dungeon", "大秘境", -10)
    frame.tabs.raid = CreateTab("raid", "团本", -45)
    frame.tabs.delve = CreateTab("delve", "地下堡", -80)
    frame.tabs.hunt = CreateTab("hunt", "狩猎", -115)

    frame.contentFrame = CreateFrame("Frame", nil, frame, "BackdropTemplate")
    frame.contentFrame:SetPoint("TOPLEFT", frame.tabBar, "TOPRIGHT", 10, 0)
    frame.contentFrame:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -10, 15)
    B.CreateBD(frame.contentFrame, .1)

    frame.scrollFrame = CreateFrame("ScrollFrame", nil, frame.contentFrame, "UIPanelScrollFrameTemplate")
    frame.scrollFrame:SetPoint("TOPLEFT", 10, -10)
    frame.scrollFrame:SetPoint("BOTTOMRIGHT", -25, 10)

    frame.content = CreateFrame("Frame")
    frame.content:SetSize(540, 500)
    frame.scrollFrame:SetScrollChild(frame.content)

    B.ReskinScroll(frame.scrollFrame.ScrollBar)

    frame.chestFrames = {}
    frame:Hide()

    M:ItemInspector_UpdateTabHighlight()

    return frame
end

function M:ItemInspector_UpdateTabHighlight()
    if not frame or not frame.tabs then return end

    for id, tab in pairs(frame.tabs) do
        if id == frame.activeTab then
            B.CreateBD(tab, .6)
            tab.text:SetTextColor(1, 0.8, 0)
        else
            B.CreateBD(tab, .3)
            tab.text:SetTextColor(0.7, 0.7, 0.7)
        end
    end
end

function M:ItemInspector_SwitchTab(tabID)
    if not frame then return end
    frame.activeTab = tabID
    M:ItemInspector_UpdateTabHighlight()
    M:ItemInspector_UpdateDisplay()
end

function M:ItemInspector_CreateChestFrame(parent, dungeonName, chestData, index)
    local chestFrame = CreateFrame("Frame", nil, parent, "BackdropTemplate")
    chestFrame:SetHeight(200)
    B.CreateBD(chestFrame, .2)

    chestFrame.icon = chestFrame:CreateTexture(nil, "ARTWORK")
    chestFrame.icon:SetSize(32, 32)
    chestFrame.icon:SetPoint("TOPLEFT", 10, -10)

    local itemID = chestData.chestID or DUNGEON_CHEST_IDS[dungeonName] or RAID_CHEST_IDS[dungeonName]
    if itemID then
        local _, _, _, _, _, _, _, _, _, itemIcon = C_Item_GetItemInfo(itemID)
        if itemIcon then
            chestFrame.icon:SetTexture(itemIcon)
        else
            chestFrame.icon:SetTexture("Interface\\Icons\\INV_Misc_Gift_05")
        end
    else
        chestFrame.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
    end
    chestFrame.icon:SetTexCoord(unpack(DB.TexCoord))
    chestFrame.iconBg = B.ReskinIcon(chestFrame.icon)

    chestFrame.dungeonName = B.CreateFS(chestFrame, 14, dungeonName, true, "TOPLEFT", 50, -15)
    chestFrame.dungeonName:SetTextColor(1, 0.8, 0)

    local chestNameText = chestData.chestName or "晦暗虚空宝箱"
    if chestData.chestID then
        chestNameText = chestNameText .. " (ID: " .. chestData.chestID .. ")"
    end
    chestFrame.chestName = B.CreateFS(chestFrame, 10, chestNameText, false, "TOPLEFT", 50, -32)

    chestFrame.contentsTitle = B.CreateFS(chestFrame, 10, "可能掉落:", false, "TOPLEFT", 10, -50)
    chestFrame.contentsTitle:SetTextColor(0.8, 0.8, 0.6)

    chestFrame.itemTexts = {}
    local startY = -65
    local lineHeight = 16

    for i = 1, 8 do
        local eb = CreateFrame("EditBox", nil, chestFrame)
        eb:SetSize(250, lineHeight)
        eb:SetPoint("TOPLEFT", 15, startY - (i-1) * lineHeight)
        eb:SetFontObject("GameFontNormalSmall")
        eb:SetTextColor(0.64, 0.21, 0.93)
        eb:SetAutoFocus(false)
        eb:SetMultiLine(false)
        eb:EnableMouse(true)
        eb:SetHyperlinksEnabled(false)
        eb:SetText("")
        chestFrame.itemTexts[i] = eb
    end

    for i = 9, 16 do
        local eb = CreateFrame("EditBox", nil, chestFrame)
        eb:SetSize(250, lineHeight)
        eb:SetPoint("TOPLEFT", 270, startY - (i-9) * lineHeight)
        eb:SetFontObject("GameFontNormalSmall")
        eb:SetTextColor(0.64, 0.21, 0.93)
        eb:SetAutoFocus(false)
        eb:SetMultiLine(false)
        eb:EnableMouse(true)
        eb:SetHyperlinksEnabled(false)
        eb:SetText("")
        chestFrame.itemTexts[i] = eb
    end

    local contentCount = #chestData.contents
    for i, itemData in ipairs(chestData.contents) do
        if chestFrame.itemTexts[i] then
            chestFrame.itemTexts[i]:SetText("• " .. itemData.name)
        end
    end

    for i = contentCount + 1, 16 do
        if chestFrame.itemTexts[i] then
            chestFrame.itemTexts[i]:SetText("")
        end
    end

    if contentCount == 0 then
        if chestFrame.itemTexts[1] then
            chestFrame.itemTexts[1]:SetText("• 轮询加载中...")
            chestFrame.itemTexts[1]:SetTextColor(0.5, 0.8, 1)
        end
    end

    return chestFrame
end

function M:ItemInspector_UpdateDisplay()
    if not frame then return end

    for _, chestFrame in ipairs(frame.chestFrames) do
        chestFrame:Hide()
    end

    local dungeonData, raidData, delveData, huntData = M:ItemInspector_GetAllChestData()

    local currentData
    if frame.activeTab == "dungeon" then
        currentData = dungeonData
    elseif frame.activeTab == "raid" then
        currentData = raidData
    elseif frame.activeTab == "delve" then
        currentData = delveData
    else
        currentData = huntData
    end

    local currentY = 0
    local index = 0

    local sortedNames = {}
    for name in pairs(currentData) do
        tinsert(sortedNames, name)
    end
    table.sort(sortedNames)

    for _, name in ipairs(sortedNames) do
        local chestData = currentData[name]
        index = index + 1
        local chestFrame = frame.chestFrames[index]
        if not chestFrame then
            chestFrame = M:ItemInspector_CreateChestFrame(frame.content, name, chestData, index)
            frame.chestFrames[index] = chestFrame
        else
            M:ItemInspector_UpdateChestFrame(chestFrame, name, chestData)
        end

        chestFrame:SetPoint("TOPLEFT", 5, -currentY - 5)
        chestFrame:SetPoint("TOPRIGHT", -5, -currentY - 5)
        chestFrame:Show()
        currentY = currentY + 205
    end

    local cachedCount = 0
    local contentCount = 0
    local totalChests = 0
    local tabName = ""

    local targetIDs = {}
    if frame.activeTab == "dungeon" then
        for _, id in pairs(DUNGEON_CHEST_IDS) do tinsert(targetIDs, id) end
        totalChests = 8
        tabName = "大秘境"
    elseif frame.activeTab == "raid" then
        for _, id in pairs(RAID_CHEST_IDS) do tinsert(targetIDs, id) end
        totalChests = 5
        tabName = "团本"
    elseif frame.activeTab == "delve" then
        for _, id in pairs(DELVE_CHEST_IDS) do tinsert(targetIDs, id) end
        totalChests = 1
        tabName = "地下堡"
    else
        for _, id in pairs(HUNT_CHEST_IDS) do tinsert(targetIDs, id) end
        totalChests = 1
        tabName = "狩猎"
    end

    for _, id in ipairs(targetIDs) do
        if chestContentsCache[id] then
            cachedCount = cachedCount + 1
            if #chestContentsCache[id].contents > 0 then
                contentCount = contentCount + 1
            end
        end
    end

    local pollingCount = #pollQueue
    if pollingCount > 0 then
        frame.hintText:SetText(string.format("%s: %d/%d 有内容, 轮询中: %d", tabName, contentCount, totalChests, pollingCount))
        frame.hintText:SetTextColor(1, 0.8, 0.3)
    else
        frame.hintText:SetText(string.format("%s: %d/%d 有内容", tabName, contentCount, totalChests))
        frame.hintText:SetTextColor(0.5, 1, 0.5)
    end

    local contentHeight = math.max(500, currentY + 20)
    frame.content:SetHeight(contentHeight)
end

function M:ItemInspector_UpdateChestFrame(chestFrame, dungeonName, chestData)
    if chestData.chestID then
        local _, _, _, _, _, _, _, _, _, itemIcon = C_Item_GetItemInfo(chestData.chestID)
        if itemIcon then
            chestFrame.icon:SetTexture(itemIcon)
        end
    end

    if chestFrame.dungeonName then
        chestFrame.dungeonName:SetText(dungeonName)
    end

    local chestNameText = chestData.chestName or "晦暗虚空宝箱"
    if chestData.chestID then
        chestNameText = chestNameText .. " (ID: " .. chestData.chestID .. ")"
    end
    chestFrame.chestName:SetText(chestNameText)

    local contentCount = #chestData.contents
    for i, itemData in ipairs(chestData.contents) do
        if chestFrame.itemTexts[i] then
            chestFrame.itemTexts[i]:SetText("• " .. itemData.name)
            chestFrame.itemTexts[i]:SetTextColor(0.64, 0.21, 0.93)
        end
    end

    for i = contentCount + 1, 16 do
        if chestFrame.itemTexts[i] then
            chestFrame.itemTexts[i]:SetText("")
        end
    end

    if contentCount == 0 then
        if chestFrame.itemTexts[1] then
            local isPolling = false
            if chestData.chestID then
                for _, id in ipairs(pollQueue) do
                    if id == chestData.chestID then
                        isPolling = true
                        break
                    end
                end
            end
            if isPolling then
                chestFrame.itemTexts[1]:SetText("• 轮询加载中...")
                chestFrame.itemTexts[1]:SetTextColor(0.5, 0.8, 1)
            else
                chestFrame.itemTexts[1]:SetText("• 悬停宝箱自动获取内容")
                chestFrame.itemTexts[1]:SetTextColor(0.7, 0.7, 0.7)
            end
        end
    end
end

function M:ItemInspector_Toggle()
    if not frame then
        M:ItemInspector_CreateFrame()
    end

    if frame:IsShown() then
        frame:Hide()
    else
        frame:Show()
        M:ItemInspector_ForcePollAll()
    end
end

local ldb = LibStub:GetLibrary("LibDataBroker-1.1")
local icon = LibStub("LibDBIcon-1.0")
local ItemInspectoricon = ldb:NewDataObject("ItemInspector", {
	label = "晦暗虚空宝箱一览", 
	type = "data source",
	icon = "Interface\\AddOns\\OrzUI\\Media\\Modules\\ItemInspector.blp",  --Interface\\Buttons\\UI-GroupLoot-Dice-Up
	--text = "Teleport"
})

function ItemInspectoricon:OnEnter()
    GameTooltip:SetOwner(self, "ANCHOR_NONE")
    GameTooltip:SetPoint("TOPLEFT", self, "BOTTOMLEFT")
    GameTooltip:ClearLines()
    GameTooltip:AddDoubleLine("晦暗虚空宝箱一览")
   GameTooltip:Show()
end

function ItemInspectoricon:OnLeave()
    GameTooltip:Hide()
end

function ItemInspectoricon:OnClick(button)
      M:ItemInspector_Toggle()
end

function M:ItemInspector_OnLogin()
    for _, chestID in pairs(DUNGEON_CHEST_IDS) do
        if chestID then
            C_Item_GetItemInfo(chestID)
        end
    end
    for _, chestID in pairs(RAID_CHEST_IDS) do
        if chestID then
            C_Item_GetItemInfo(chestID)
        end
    end
    for _, chestID in pairs(DELVE_CHEST_IDS) do
        if chestID then
            C_Item_GetItemInfo(chestID)
        end
    end
    for _, chestID in pairs(HUNT_CHEST_IDS) do
        if chestID then
            C_Item_GetItemInfo(chestID)
        end
    end
    icon:Register("ItemInspector", ItemInspectoricon)		--, TomeOfTele_Icon
end

M:RegisterMisc("ItemInspector", M.ItemInspector_OnLogin)

SLASH_ORZUIVOIDCHEST1 = "/voidchest"
SLASH_ORZUIVOIDCHEST2 = "/vc"
SlashCmdList["ORZUIVOIDCHEST"] = function(msg)
    M:ItemInspector_Toggle()
end

TooltipDataProcessor.AddTooltipPostCall(Enum.TooltipDataType.Item, function(tooltip, data)
    if not data or not data.guid then return end

    local _, itemID = strmatch(data.guid, "^Item%-%-%-%-(%d+)%-%-(%d+)")
    itemID = tonumber(itemID)

    if not itemID then return end
    if not ALL_CHEST_IDS[itemID] then return end

    local isVoidChest = false
    local dungeonName = nil
    local contents = {}
    local itemListStarted = false

    for _, line in ipairs(data.lines or {}) do
        local text = line.leftText or ""

        if strfind(text, "晦暗虚空宝箱") then
            isVoidChest = true
            dungeonName = strmatch(text, "：(.+)$") or strmatch(text, ":(.+)$")
        end

        if isVoidChest and (strfind(text, "内含下列物品") or strfind(text, "Contains one of the following")) then
            itemListStarted = true
        elseif isVoidChest and itemListStarted and strfind(text, "^%-") then
            local itemName = text:gsub("^%-%s*", "")
            itemName = itemName:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", "")
            if itemName and itemName ~= "" then
                tinsert(contents, {
                    name = itemName,
                    itemID = nil,
                })
            end
        elseif isVoidChest and itemListStarted and text ~= "" and not strfind(text, "^%-") then
            if strfind(text, "物品ID") or strfind(text, "史诗钥石") or strfind(text, "物品等级") then
                -- continue
            else
                itemListStarted = false
            end
        end
    end

    if isVoidChest then
        local itemLink = select(2, C_Item_GetItemInfo(itemID))
        local knownName = ALL_CHEST_IDS[itemID] or dungeonName or ""

        chestContentsCache[itemID] = {
            chestName = "晦暗虚空宝箱：" .. knownName,
            dungeonName = dungeonName or knownName,
            contents = contents,
            itemLink = itemLink,
            chestID = itemID,
        }

        for i, id in ipairs(pollQueue) do
            if id == itemID then
                tremove(pollQueue, i)
                pollAttempts[itemID] = nil
                break
            end
        end

        if frame and frame:IsShown() then
            M:ItemInspector_UpdateDisplay()
        end
    end
end)

local scanInProgress = false
function M:ItemInspector_ScanForChestIDs(startID, endID)
    if scanInProgress then
        print("ItemInspector: 扫描已在进行中")
        return
    end

    startID = startID or 268460
    endID = endID or 268480

    print("ItemInspector: 开始扫描宝箱ID范围 " .. startID .. " - " .. endID)
    scanInProgress = true

    local currentID = startID
    local foundCount = 0

    local function ScanNext()
        if currentID > endID then
            scanInProgress = false
            print("ItemInspector: 扫描完成，发现 " .. foundCount .. " 个宝箱")
            return
        end

        local scanTooltip = _G["OrzUIItemInspectorScanTooltip"]
        if scanTooltip then
            scanTooltip:ClearLines()
            scanTooltip:SetOwner(UIParent, "ANCHOR_NONE")
            scanTooltip:SetItemByID(currentID)

            for i = 1, scanTooltip:NumLines() do
                local line = _G["OrzUIItemInspectorScanTooltipTextLeft" .. i]
                if line then
                    local text = line:GetText() or ""
                    if strfind(text, "晦暗虚空宝箱") then
                        local dungeonName = strmatch(text, "：(.+)$") or strmatch(text, ":(.+)$")
                        if dungeonName then
                            DUNGEON_CHEST_IDS[dungeonName] = currentID
                            ALL_CHEST_IDS[currentID] = dungeonName
                            foundCount = foundCount + 1
                            print("ItemInspector: 发现宝箱 - " .. dungeonName .. " = " .. currentID)
                        end
                        break
                    end
                end
            end
        end

        currentID = currentID + 1
        C_Timer.After(0.01, ScanNext)
    end

    ScanNext()
end

SLASH_ORZUISCANCHEST1 = "/scanchest"
SlashCmdList["ORZUISCANCHEST"] = function(msg)
    local startID, endID = strmatch(msg, "(%d+)%s+(%d+)")
    if startID and endID then
        M:ItemInspector_ScanForChestIDs(tonumber(startID), tonumber(endID))
    else
        M:ItemInspector_ScanForChestIDs()
    end
end
