--[[
============================================================
Decor Vendor Addon
© 2026 MidniteDestiny. All Rights Reserved.
============================================================

This file is part of the Decor Vendor addon.

All code, structure, and design are the intellectual
property of MidniteDestiny unless otherwise stated.

You may NOT:
• Copy, reproduce, or redistribute this code
• Modify and redistribute this code
• Use this code in other addons or projects

without explicit permission from the author.

This addon is distributed for personal use only.

============================================================
]]

local addonName, dv = ...

local C = dv.CONSTANTS

dv.decorThumbCache = dv.decorThumbCache or {}
dv.itemNameCache = dv.itemNameCache or {}
dv.vendorSessionCache = dv.vendorSessionCache or {}

local decorThumbCache = dv.decorThumbCache
local itemNameCache = dv.itemNameCache
local vendorSessionCache = dv.vendorSessionCache

local refreshTimer = nil

-------------------------------------------------
-- Refresh / cache helpers
-------------------------------------------------

function dv.RequestUpdate()
    if refreshTimer then
        refreshTimer:Cancel()
    end

    refreshTimer = C_Timer.NewTimer(0.2, function()
        refreshTimer = nil

        if DV_MainFrame and DV_MainFrame:IsShown() then
            if BuildVendorUI then
                BuildVendorUI()
            elseif dv.BuildVendorUI then
                dv.BuildVendorUI()
            end
        end
    end)
end

-- Compatibility wrapper
function RequestUpdate()
    return dv.RequestUpdate()
end

function dv.IsCatalogUsable()
    if not C_HousingCatalog or not C_HousingCatalog.GetCatalogEntryInfoByRecordID then
        return false
    end

    local test = C_HousingCatalog.GetCatalogEntryInfoByRecordID(1, 1, true)
    return test ~= nil
end

-- Compatibility wrapper
function IsCatalogUsable()
    return dv.IsCatalogUsable()
end

function dv.GetCachedItemName(itemID)
    if not itemID then
        return "Unknown Item", false
    end

    if itemNameCache[itemID] then
        return itemNameCache[itemID], false
    end

    local item = Item:CreateFromItemID(itemID)

    if not item:IsItemEmpty() then
        item:ContinueOnItemLoad(function()
            itemNameCache[itemID] = item:GetItemName()
            dv.RequestUpdate()
        end)
    end

    return "Loading...", true
end

-- Compatibility wrapper
function GetCachedItemName(itemID)
    return dv.GetCachedItemName(itemID)
end

function dv.GetDecorThumbnail(itemID)
    if decorThumbCache[itemID] then
        return decorThumbCache[itemID]
    end

    local decorData = dv.ActiveItems and dv.ActiveItems[itemID]
    if not decorData or not decorData.decorID then
        return nil
    end

    local info = C_HousingCatalog.GetCatalogEntryInfoByRecordID(
        1,
        decorData.decorID,
        true
    )

    if info and info.iconTexture then
        decorThumbCache[itemID] = info.iconTexture
        return info.iconTexture
    end

    return nil
end

-- Compatibility wrapper
function GetDecorThumbnail(itemID)
    return dv.GetDecorThumbnail(itemID)
end

-------------------------------------------------
-- Decor / ownership helpers
-------------------------------------------------

function dv.GetDecorIconByItemID(itemID)
    local decorData = dv.ActiveItems and dv.ActiveItems[itemID]

    if not decorData or not decorData.decorID then
        return nil
    end

    local info = C_HousingCatalog.GetCatalogEntryInfoByRecordID(
        1,
        decorData.decorID,
        true
    )

    return info and info.iconTexture
end

function dv.IsDecorOwned(itemID)
    if not dv.catalogReady then
        return false
    end

    if not itemID then
        return false
    end

    local data = dv.ActiveItems and dv.ActiveItems[itemID]

    if not data or not data.decorID then
        return false
    end

    if C_HousingCatalog and C_HousingCatalog.GetCatalogEntryInfoByRecordID then
        local info = C_HousingCatalog.GetCatalogEntryInfoByRecordID(
            Enum.HousingCatalogEntryType.Decor,
            data.decorID,
            true
        )

        if type(info) == "table" then
            local owned =
                (tonumber(info.numPlaced) or 0) +
                (tonumber(info.numStored) or 0) +
                (tonumber(info.ownedCount) or 0) +
                (tonumber(info.quantity) or 0)

            return owned > 0
        end
    end

    return false
end

function dv.GetVendorStatus(vendorID)
    if not dv.catalogReady then
        return false, 0
    end

    if vendorSessionCache[vendorID] then
        return vendorSessionCache[vendorID].isComplete,
               vendorSessionCache[vendorID].missingCount
    end

    local vendorData = dv.vendorGoodies and dv.vendorGoodies[vendorID]
    local items = vendorData and (vendorData.items or vendorData)

    if not items then
        return false, 0
    end

    local missingCount = 0
    local relevantCount = 0

    for _, itemID in ipairs(items) do
        local decor = dv.ActiveItems and dv.ActiveItems[itemID]

        if decor and decor.decorID then
            relevantCount = relevantCount + 1

            if not dv.IsDecorOwned(itemID) then
                missingCount = missingCount + 1
            end
        end
    end

    local isComplete = relevantCount > 0 and missingCount == 0

    vendorSessionCache[vendorID] = {
        isComplete = isComplete,
        missingCount = missingCount,
    }

    return isComplete, missingCount
end

-- Compatibility wrapper
function GetVendorStatus(vendorID)
    return dv.GetVendorStatus(vendorID)
end

-------------------------------------------------
-- Vendor / faction helpers
-------------------------------------------------

function dv.GetVendorInfo(vendorID)
    if not vendorID or not dv.npcs then
        return nil
    end

    for _, group in ipairs(dv.npcs) do
        for _, vendor in ipairs(group.vendors or {}) do
            if vendor.id == vendorID then
                vendor.groupName = group.name
                vendor.expansion = group.expansion
                return vendor
            end
        end
    end

    return nil
end

function dv.GetFactionColor(faction)
    faction = faction and string.lower(faction)

    if faction == "alliance" then
        return unpack(C.COLORS.ALLIANCE)

    elseif faction == "horde" then
        return unpack(C.COLORS.HORDE)

    else
        return unpack(C.COLORS.NEUTRAL)
    end
end

function ResetAllVendors()
    vendorSettings.visited = {}
    print("|cff88ff88DecorVendor:|r Vendor progress reset.")
end

function dv.ClearWidgets()
    for _, w in ipairs(dv.activeWidgets or {}) do
        if w and w.Hide then
            w:Hide()
        end
    end

    wipe(dv.activeWidgets)
end

function dv.GetPlayerRenownLevel(factionID)
    local data = C_MajorFactions.GetMajorFactionData(factionID)

    if data then
        return data.renownLevel or 0
    end

    return 0
end

function dv.GetSubfactionTier(factionID)
    local data = C_MajorFactions.GetMajorFactionData(factionID)

    if data then
        return data.renownLevel or 0
    end

    return 0
end

function dv.GetVendorRequirementType(vendorID)
    local vendorData = dv.vendorGoodies and dv.vendorGoodies[vendorID]
    local items = vendorData and (vendorData.items or vendorData)

    if not items then
        return "none"
    end

    local foundType = nil

    for _, itemID in ipairs(items) do
        local itemData = dv.ActiveItems and dv.ActiveItems[itemID]

        if itemData then
            local req = itemData.requirement

            if req and req.type then
                local t = string.lower(req.type)

                -- subfaction wins immediately
                if t == "subfaction" then
                    return "subfaction"
                end

                foundType = t
            end
        end
    end

    return foundType or "none"
end

-------------------------------------------------
-- Links
-------------------------------------------------

function dv:GetWowheadLink(id, rewardType)
    if rewardType == "quest" then
        return "https://www.wowhead.com/quest=" .. tostring(id)

    elseif rewardType == "item" then
        return "https://www.wowhead.com/item=" .. tostring(id)

    else
        return "https://www.wowhead.com/achievement=" .. tostring(id)
    end
end

function dv.ShowWowheadBox(parent, wowheadBox, id, rewardType)
    if not wowheadBox or not id then
        return
    end

    local url = dv:GetWowheadLink(id, rewardType)

    if dv.activeWowheadBox and dv.activeWowheadBox ~= wowheadBox then
        dv.activeWowheadBox:Hide()
    end

    wowheadBox:SetText(url)
    wowheadBox:Show()
    wowheadBox:SetFocus()
    wowheadBox:HighlightText()

    dv.activeWowheadBox = wowheadBox
end

-- Compatibility wrapper.
-- Older row code still calls ShowWowheadBox(...) directly.
function ShowWowheadBox(parent, wowheadBox, id, rewardType)
    return dv.ShowWowheadBox(parent, wowheadBox, id, rewardType)
end