-- ============================================================
-- Decor Vendor Data
-- Debug.lua
-- Debug commands, catalog checks, and copy/paste exports
-- ============================================================
--
-- Slash Commands:
--
-- /dvdata
--   Shows this command list.
--
-- /dvdata count
--   Prints total ActiveItems, unique decorIDs, and missing decorID count.
--
-- /dvdata catalog
--   Checks which DecorVendorData decorIDs are visible in the current Housing Catalog.
--
-- /dvdata groups
--   Prints item counts for every registered data group/file.
--
-- /dvdata group Midnight
--   Prints the item count for one specific group.
--   Example: /dvdata group The Burning Crusade
--
-- /dvdata hidden
--   Prints page 1 of decor items hidden/missing from the current Housing Catalog.
--
-- /dvdata hidden 2
--   Prints page 2 of hidden/missing catalog items.
--
-- /dvdata hidden groups
--   Prints hidden/missing item counts grouped by data file/category.
--
-- /dvhidden
--   Opens a copy/paste popout box with all hidden/missing catalog items.
--
-- ============================================================

local addonName, DVD = ...

_G.DecorVendorData = DVD
_G[addonName] = DVD

DVD.ActiveItems = DVD.ActiveItems or {}
DVD.ActiveItemsByExpansion = DVD.ActiveItemsByExpansion or {}

-- ============================================================
-- Basic Counts
-- ============================================================

function DVD.DebugCounts()
    local total = 0
    local noDecorID = 0
    local uniqueDecorIDs = 0
    local seenDecorIDs = {}

    for itemID, data in pairs(DVD.ActiveItems or {}) do
        total = total + 1

        if data.decorID then
            if not seenDecorIDs[data.decorID] then
                seenDecorIDs[data.decorID] = true
                uniqueDecorIDs = uniqueDecorIDs + 1
            end
        else
            noDecorID = noDecorID + 1
        end
    end

    print("|cffffd100DecorVendorData Counts|r")
    print("Active itemIDs:", total)
    print("Unique decorIDs:", uniqueDecorIDs)
    print("Missing decorID:", noDecorID)
end

function DVD.DebugCatalogMatch()
    if not C_HousingCatalog or not C_HousingCatalog.GetCatalogEntryInfoByRecordID then
        print("|cffff4040DecorVendorData: Housing Catalog API is not available.|r")
        return
    end

    local checked = 0
    local found = 0
    local missing = 0

    for itemID, data in pairs(DVD.ActiveItems or {}) do
        if data.decorID then
            checked = checked + 1

            local ok, info = pcall(C_HousingCatalog.GetCatalogEntryInfoByRecordID, 1, data.decorID, true)

            if ok and info then
                found = found + 1
            else
                missing = missing + 1
            end
        end
    end

    print("|cffffd100DecorVendorData Catalog Match|r")
    print("Checked decorIDs:", checked)
    print("Found in this catalog:", found)
    print("Missing/hidden on this build:", missing)
end

-- ============================================================
-- Group Counts
-- ============================================================

function DVD.DebugGroup(groupName)
    if not groupName or groupName == "" then
        print("|cffffcc00Usage:|r /dvdata group Midnight")
        return
    end

    local groups = DVD.ActiveItemsByExpansion or {}
    local group = groups[groupName]

    if not group then
        local lowerWanted = string.lower(groupName)

        for name, data in pairs(groups) do
            if string.lower(name) == lowerWanted then
                groupName = name
                group = data
                break
            end
        end
    end

    if not group then
        print("|cffff4040DecorVendorData: No group found named:|r", groupName)
        return
    end

    local count = 0

    for _ in pairs(group) do
        count = count + 1
    end

    print("|cffffd100DecorVendorData Group|r", groupName, "=", count, "items")
end

function DVD.DebugGroups()
    print("|cffffd100DecorVendorData Groups|r")

    local names = {}

    for groupName in pairs(DVD.ActiveItemsByExpansion or {}) do
        table.insert(names, groupName)
    end

    table.sort(names)

    for _, groupName in ipairs(names) do
        local count = 0
        local group = DVD.ActiveItemsByExpansion[groupName]

        for _ in pairs(group or {}) do
            count = count + 1
        end

        print(groupName .. ":", count)
    end
end

-- ============================================================
-- Hidden / Missing Catalog Items
-- ============================================================

function DVD.GetHiddenCatalogItems()
    local hidden = {}

    if not C_HousingCatalog or not C_HousingCatalog.GetCatalogEntryInfoByRecordID then
        print("|cffff4040DecorVendorData: Housing Catalog API is not available.|r")
        return hidden
    end

    for itemID, data in pairs(DVD.ActiveItems or {}) do
        if data.decorID then
            local ok, info = pcall(C_HousingCatalog.GetCatalogEntryInfoByRecordID, 1, data.decorID, true)

            if not ok or not info then
                table.insert(hidden, {
                    itemID = itemID,
                    data = data,
                    group = data.expansion or (DVD.ActiveItemSources and DVD.ActiveItemSources[itemID]) or "Unknown",
                })

                if C_Item and C_Item.RequestLoadItemDataByID then
                    C_Item.RequestLoadItemDataByID(itemID)
                end
            end
        end
    end

    table.sort(hidden, function(a, b)
        if a.group == b.group then
            return a.itemID < b.itemID
        end

        return tostring(a.group) < tostring(b.group)
    end)

    return hidden
end

function DVD.DebugHiddenCatalogItems(page)
    page = tonumber(page) or 1

    local hidden = DVD.GetHiddenCatalogItems()
    local perPage = 20
    local total = #hidden
    local totalPages = math.max(1, math.ceil(total / perPage))

    if page < 1 then
        page = 1
    end

    if page > totalPages then
        page = totalPages
    end

    print("|cffffd100DecorVendorData Hidden Catalog Items|r")
    print("Hidden/missing on this build:", total, "Page:", page .. "/" .. totalPages)

    local startIndex = ((page - 1) * perPage) + 1
    local endIndex = math.min(startIndex + perPage - 1, total)

    for i = startIndex, endIndex do
        local entry = hidden[i]
        local itemName = C_Item and C_Item.GetItemNameByID and C_Item.GetItemNameByID(entry.itemID)

        itemName = itemName or ("itemID " .. entry.itemID)

        print(
            i .. ".",
            "|cff66ccff" .. tostring(entry.group) .. "|r",
            itemName,
            "itemID:", entry.itemID,
            "decorID:", entry.data.decorID,
            "source:", tostring(entry.data.source)
        )
    end

    if page < totalPages then
        print("|cffffcc00Next page:|r /dvdata hidden " .. (page + 1))
    end
end

function DVD.DebugHiddenByGroup()
    local hidden = DVD.GetHiddenCatalogItems()
    local counts = {}
    local names = {}

    for _, entry in ipairs(hidden) do
        local group = entry.group or "Unknown"

        if not counts[group] then
            table.insert(names, group)
            counts[group] = 0
        end

        counts[group] = counts[group] + 1
    end

    table.sort(names)

    print("|cffffd100DecorVendorData Hidden By Group|r")

    for _, group in ipairs(names) do
        print(group .. ":", counts[group])
    end
end

-- ============================================================
-- Lua Export Helpers
-- ============================================================

local function DVD_TableKeySort(a, b)
    return tostring(a) < tostring(b)
end

local function DVD_SerializeValue(value)
    local valueType = type(value)

    if valueType == "string" then
        return string.format("%q", value)
    elseif valueType == "number" or valueType == "boolean" then
        return tostring(value)
    elseif valueType == "table" then
        local parts = {}
        local isArray = true
        local maxIndex = 0

        for k in pairs(value) do
            if type(k) ~= "number" then
                isArray = false
                break
            end

            if k > maxIndex then
                maxIndex = k
            end
        end

        if isArray then
            for i = 1, maxIndex do
                table.insert(parts, DVD_SerializeValue(value[i]))
            end

            return "{" .. table.concat(parts, ", ") .. "}"
        end

        local keys = {}

        for k in pairs(value) do
            if k ~= "expansion" then
                table.insert(keys, k)
            end
        end

        table.sort(keys, DVD_TableKeySort)

        for _, k in ipairs(keys) do
            local keyText

            if type(k) == "string" and string.match(k, "^[%a_][%w_]*$") then
                keyText = k
            else
                keyText = "[" .. DVD_SerializeValue(k) .. "]"
            end

            table.insert(parts, keyText .. " = " .. DVD_SerializeValue(value[k]))
        end

        return "{ " .. table.concat(parts, ", ") .. " }"
    end

    return "nil"
end

function DVD.BuildHiddenCatalogExport()
    local hidden = DVD.GetHiddenCatalogItems()
    local lines = {}

    table.insert(lines, "-- ============================================================")
    table.insert(lines, "-- DecorVendorData hidden/missing catalog items")
    table.insert(lines, "-- These are in DecorVendorData.ActiveItems but hidden/missing")
    table.insert(lines, "-- from the Housing Catalog API on this current build/realm.")
    table.insert(lines, "-- Total hidden/missing: " .. tostring(#hidden))
    table.insert(lines, "-- ============================================================")
    table.insert(lines, "")

    local lastGroup

    for _, entry in ipairs(hidden) do
        local itemID = entry.itemID
        local data = entry.data
        local group = entry.group or "Unknown"

        if group ~= lastGroup then
            if lastGroup then
                table.insert(lines, "")
            end

            table.insert(lines, "-- " .. tostring(group))
            lastGroup = group
        end

        local itemName = C_Item and C_Item.GetItemNameByID and C_Item.GetItemNameByID(itemID)
        local nameComment = itemName and (" -- " .. itemName) or ""

        table.insert(lines, "[" .. itemID .. "] = " .. DVD_SerializeValue(data) .. "," .. nameComment)
    end

    return table.concat(lines, "\n")
end

-- ============================================================
-- Copy Box
-- ============================================================

function DVD.ShowCopyBox(title, text)
    if not DVD.CopyFrame then
        local frame = CreateFrame("Frame", "DecorVendorDataCopyFrame", UIParent, "BackdropTemplate")
        frame:SetSize(850, 620)
        frame:SetPoint("CENTER")
        frame:SetFrameStrata("DIALOG")
        frame:SetFrameLevel(500)
        frame:SetMovable(true)
        frame:EnableMouse(true)
        frame:RegisterForDrag("LeftButton")
        frame:SetScript("OnDragStart", frame.StartMoving)
        frame:SetScript("OnDragStop", frame.StopMovingOrSizing)

        frame:SetBackdrop({
            bgFile = "Interface\\Buttons\\WHITE8x8",
            edgeFile = "Interface\\Buttons\\WHITE8x8",
            edgeSize = 1,
        })

        frame:SetBackdropColor(0.02, 0.015, 0.035, 0.98)
        frame:SetBackdropBorderColor(0.9, 0.7, 0.2, 1)

        frame.title = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
        frame.title:SetPoint("TOP", 0, -14)
        frame.title:SetText("|cffffd100DecorVendorData Export|r")

        frame.instructions = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        frame.instructions:SetPoint("TOP", frame.title, "BOTTOM", 0, -6)
        frame.instructions:SetText("|cffccccccClick inside the box, press Ctrl+A, then Ctrl+C.|r")

        local scroll = CreateFrame("ScrollFrame", nil, frame, "UIPanelScrollFrameTemplate")
        scroll:SetPoint("TOPLEFT", 18, -58)
        scroll:SetPoint("BOTTOMRIGHT", -32, 48)

        local editBox = CreateFrame("EditBox", nil, scroll)
        editBox:SetMultiLine(true)
        editBox:SetAutoFocus(false)
        editBox:SetFontObject(ChatFontNormal)
        editBox:SetWidth(780)
        editBox:SetTextInsets(8, 8, 8, 8)

        editBox:SetScript("OnEscapePressed", function(self)
            self:ClearFocus()
        end)

        editBox:SetScript("OnEditFocusGained", function(self)
            self:HighlightText()
        end)

        scroll:SetScrollChild(editBox)

        frame.editBox = editBox
        frame.scroll = scroll

        frame.selectAll = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
        frame.selectAll:SetSize(110, 24)
        frame.selectAll:SetPoint("BOTTOMLEFT", 18, 14)
        frame.selectAll:SetText("Select All")
        frame.selectAll:SetScript("OnClick", function()
            frame.editBox:SetFocus()
            frame.editBox:HighlightText()
        end)

        frame.close = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
        frame.close:SetSize(90, 24)
        frame.close:SetPoint("BOTTOMRIGHT", -18, 14)
        frame.close:SetText("Close")
        frame.close:SetScript("OnClick", function()
            frame:Hide()
        end)

        DVD.CopyFrame = frame
    end

    DVD.CopyFrame.title:SetText(title or "|cffffd100DecorVendorData Export|r")
    DVD.CopyFrame.editBox:SetText(text or "")
    DVD.CopyFrame.editBox:SetCursorPosition(0)
    DVD.CopyFrame.editBox:HighlightText()
    DVD.CopyFrame:Show()
end

function DVD.OpenHiddenCatalogCopyBox()
    local text = DVD.BuildHiddenCatalogExport()
    DVD.ShowCopyBox("|cffffd100Hidden Catalog Items|r", text)
end

-- ============================================================
-- Slash Commands
-- ============================================================

SLASH_DECORVENDORDATA1 = "/dvdata"
SlashCmdList["DECORVENDORDATA"] = function(msg)
    msg = msg or ""

    local lower = string.lower(msg)

    if lower == "count" or lower == "counts" then
        DVD.DebugCounts()

    elseif lower == "catalog" then
        DVD.DebugCatalogMatch()

    elseif lower == "groups" then
        DVD.DebugGroups()

    elseif lower == "hidden groups" or lower == "hiddengroups" then
        DVD.DebugHiddenByGroup()

    elseif string.match(lower, "^hidden%s*%d*") then
        local page = string.match(msg, "^hidden%s*(%d*)$")
        DVD.DebugHiddenCatalogItems(page)

    elseif string.match(lower, "^group%s+") then
        local groupName = string.match(msg, "^group%s+(.+)$")
        DVD.DebugGroup(groupName)

    else
        print("|cffffd100DecorVendorData Commands|r")
        print("/dvdata count")
        print("/dvdata catalog")
        print("/dvdata groups")
        print("/dvdata group Midnight")
        print("/dvdata hidden")
        print("/dvdata hidden 2")
        print("/dvdata hidden groups")
        print("/dvhidden")
    end
end

SLASH_DECORVENDORHIDDEN1 = "/dvhidden"
SlashCmdList["DECORVENDORHIDDEN"] = function()
    DVD.OpenHiddenCatalogCopyBox()
end