--[[
============================================================
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 or {}
local frame = dv.frame
local itemContainer = dv.itemContainer

local COLLECTED_ICON_TEXTURE = "Interface\\AddOns\\DecorVendor\\Assets\\collected"

local ICON_SIZE = 40
local ICON_GAP = 8
local ICONS_PER_PAGE = 20

vendorFilteredItems = vendorFilteredItems or {}
currentVendorPage = currentVendorPage or 1

if not frame then
    print("|cffff4040DecorVendor VendorPopup:|r dv.frame is missing. Make sure UI\\MainFrame.lua loads first.")
    return
end

if not itemContainer then
    print("|cffff4040DecorVendor VendorPopup:|r dv.itemContainer is missing. Make sure UI\\PreviewPanel.lua loads first.")
    return
end

if not tContains(UISpecialFrames, "DV_VendorPopup") then
    tinsert(UISpecialFrames, "DV_VendorPopup")
end

-------------------------------------------------
-- Main Vendor Popup Area
-- Sits below dv.modelTitle inside itemContainer.
-------------------------------------------------

dv.vendorPopup = CreateFrame("Frame", "DV_VendorPopup", itemContainer, "BackdropTemplate")
local vendorPopup = dv.vendorPopup

vendorPopup:ClearAllPoints()
vendorPopup:SetPoint("TOPLEFT", itemContainer, "TOPLEFT", 10, -42)
vendorPopup:SetPoint("TOPRIGHT", itemContainer, "TOPRIGHT", -10, -42)
vendorPopup:SetPoint("BOTTOMRIGHT", itemContainer, "BOTTOMRIGHT", -10, 10)
vendorPopup:EnableMouseWheel(true)
vendorPopup:Hide()

dv.popupIconCache = dv.popupIconCache or {}
local popupIconCache = dv.popupIconCache

-------------------------------------------------
-- Zone / subtitle text
-------------------------------------------------

local vendorZoneText = vendorPopup:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
vendorZoneText:ClearAllPoints()
vendorZoneText:SetPoint("TOPLEFT", vendorPopup, "TOPLEFT", 0, 0)
vendorZoneText:SetPoint("TOPRIGHT", vendorPopup, "TOPRIGHT", -92, 0)
vendorZoneText:SetHeight(18)
vendorZoneText:SetJustifyH("LEFT")
vendorZoneText:SetFont(STANDARD_TEXT_FONT, 12, "OUTLINE")
vendorZoneText:SetTextColor(0.85, 0.85, 0.85, 1)
vendorZoneText:SetText("")
dv.vendorZoneText = vendorZoneText

local vendorPopupHiddenText = vendorPopup:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
vendorPopupHiddenText:SetFont(STANDARD_TEXT_FONT, 11, "")
vendorPopupHiddenText:SetTextColor(0.75, 0.75, 0.75, 1)
vendorPopupHiddenText:SetPoint("TOPLEFT", vendorZoneText, "BOTTOMLEFT", 0, -2)
vendorPopupHiddenText:SetPoint("TOPRIGHT", vendorPopup, "TOPRIGHT", -4, -2)
vendorPopupHiddenText:SetJustifyH("LEFT")
vendorPopupHiddenText:Hide()
vendorPopup.hiddenText = vendorPopupHiddenText

-------------------------------------------------
-- Content Grid Area
-------------------------------------------------

vendorPopup.content = CreateFrame("Frame", nil, vendorPopup)
vendorPopup.content:SetPoint("TOPLEFT", vendorPopup, "TOPLEFT", 0, -26)
vendorPopup.content:SetPoint("TOPRIGHT", vendorPopup, "TOPRIGHT", 0, -26)
vendorPopup.content:SetPoint("BOTTOM", vendorPopup, "BOTTOM", 0, 32)

-------------------------------------------------
-- Paging Footer
-------------------------------------------------

dv.pagingFrame = CreateFrame("Frame", nil, vendorPopup, "BackdropTemplate")
local pagingFrame = dv.pagingFrame

pagingFrame:SetSize(150, 24)
pagingFrame:SetPoint("BOTTOM", vendorPopup, "BOTTOM", 0, 2)
pagingFrame:SetFrameLevel(vendorPopup:GetFrameLevel() + 20)
pagingFrame:Hide()

pagingFrame:SetBackdrop({
    bgFile = "Interface\\Buttons\\WHITE8x8",
    edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
    tile = true,
    tileSize = 16,
    edgeSize = 8,
    insets = { left = 1, right = 1, top = 1, bottom = 1 },
})
pagingFrame:SetBackdropColor(0.035, 0.025, 0.055, 0.82)
pagingFrame:SetBackdropBorderColor(0.45, 0.33, 0.65, 0.75)

dv.vendorPrevBtn = CreateFrame("Button", nil, pagingFrame)
dv.vendorPrevBtn:SetSize(22, 22)
dv.vendorPrevBtn:SetPoint("LEFT", pagingFrame, "LEFT", 6, 0)
dv.vendorPrevBtn:SetNormalTexture("Interface\\Buttons\\UI-SpellbookIcon-PrevPage-Up")
dv.vendorPrevBtn:SetPushedTexture("Interface\\Buttons\\UI-SpellbookIcon-PrevPage-Down")
dv.vendorPrevBtn:SetDisabledTexture("Interface\\Buttons\\UI-SpellbookIcon-PrevPage-Disabled")
dv.vendorPrevBtn:SetHighlightTexture("Interface\\Buttons\\UI-Common-MouseHilight", "ADD")

dv.vendorNextBtn = CreateFrame("Button", nil, pagingFrame)
dv.vendorNextBtn:SetSize(22, 22)
dv.vendorNextBtn:SetPoint("RIGHT", pagingFrame, "RIGHT", -6, 0)
dv.vendorNextBtn:SetNormalTexture("Interface\\Buttons\\UI-SpellbookIcon-NextPage-Up")
dv.vendorNextBtn:SetPushedTexture("Interface\\Buttons\\UI-SpellbookIcon-NextPage-Down")
dv.vendorNextBtn:SetDisabledTexture("Interface\\Buttons\\UI-SpellbookIcon-NextPage-Disabled")
dv.vendorNextBtn:SetHighlightTexture("Interface\\Buttons\\UI-Common-MouseHilight", "ADD")

dv.vendorPageText = pagingFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
dv.vendorPageText:SetPoint("LEFT", dv.vendorPrevBtn, "RIGHT", 3, 0)
dv.vendorPageText:SetPoint("RIGHT", dv.vendorNextBtn, "LEFT", -3, 0)
dv.vendorPageText:SetJustifyH("CENTER")
dv.vendorPageText:SetFont(STANDARD_TEXT_FONT, 11, "OUTLINE")
dv.vendorPageText:SetText("Page 1")

local UpdateVendorPopup

dv.vendorPrevBtn:SetScript("OnClick", function()
    if currentVendorPage > 1 then
        currentVendorPage = currentVendorPage - 1
        PlaySound(SOUNDKIT.IG_ABILITY_PAGE_TURN)
        UpdateVendorPopup()
    end
end)

dv.vendorNextBtn:SetScript("OnClick", function()
    local totalPages = math.max(1, math.ceil(#vendorFilteredItems / ICONS_PER_PAGE))

    if currentVendorPage < totalPages then
        currentVendorPage = currentVendorPage + 1
        PlaySound(SOUNDKIT.IG_ABILITY_PAGE_TURN)
        UpdateVendorPopup()
    end
end)

vendorPopup:SetScript("OnMouseWheel", function(_, delta)
    local totalPages = math.max(1, math.ceil(#vendorFilteredItems / ICONS_PER_PAGE))

    if delta > 0 then
        if currentVendorPage > 1 then
            currentVendorPage = currentVendorPage - 1
            PlaySound(SOUNDKIT.IG_ABILITY_PAGE_TURN)
            UpdateVendorPopup()
        end
    else
        if currentVendorPage < totalPages then
            currentVendorPage = currentVendorPage + 1
            PlaySound(SOUNDKIT.IG_ABILITY_PAGE_TURN)
            UpdateVendorPopup()
        end
    end
end)

-------------------------------------------------
-- Icon Frames
-------------------------------------------------

local function GetPopupIconFrame(index)
    local container = popupIconCache[index]

    if container then
        container:Show()
        return container
    end

    container = CreateFrame("Frame", nil, vendorPopup.content)
    container:SetSize(ICON_SIZE, ICON_SIZE + 10)

    local borderFrame = CreateFrame("Frame", nil, container, "BackdropTemplate")
    borderFrame:SetSize(ICON_SIZE, ICON_SIZE)
    borderFrame:SetPoint("TOP", container, "TOP", 0, 0)
    borderFrame:SetBackdrop({
        edgeFile = "Interface\\Buttons\\WHITE8x8",
        edgeSize = 2,
    })
    borderFrame:SetBackdropBorderColor(0.4, 0.4, 0.4, 1)
    borderFrame:SetClipsChildren(true)
    container.borderFrame = borderFrame

    local btn = CreateFrame("Button", nil, borderFrame)
    btn:SetAllPoints(borderFrame)
    btn:RegisterForClicks("AnyUp")
    container.btn = btn

    local glow = btn:CreateTexture(nil, "BACKGROUND")
    glow:SetPoint("TOPLEFT", -2, 2)
    glow:SetPoint("BOTTOMRIGHT", 2, -2)
    glow:SetColorTexture(0, 0, 0, 0.5)
    container.glow = glow

    local icon = btn:CreateTexture(nil, "ARTWORK")
    icon:SetPoint("TOPLEFT", 2, -2)
    icon:SetPoint("BOTTOMRIGHT", -2, 2)
    icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
    container.icon = icon

    local checkFrame = CreateFrame("Frame", nil, container)
    checkFrame:SetSize(18, 18)
    checkFrame:SetPoint("BOTTOM", borderFrame, "BOTTOM", 0, -8)
    checkFrame:SetFrameLevel(borderFrame:GetFrameLevel() + 10)
    checkFrame:Hide()

    local checkTex = checkFrame:CreateTexture(nil, "ARTWORK")
    checkTex:SetAllPoints()
    checkTex:SetTexture(COLLECTED_ICON_TEXTURE)
    checkFrame.texture = checkTex
    container.checkFrame = checkFrame

    btn:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square")
    btn:GetHighlightTexture():SetBlendMode("ADD")
    btn:GetHighlightTexture():SetAllPoints(icon)

    popupIconCache[index] = container

    return container
end

function PopupButton_OnEnter(self)
    local container = self:GetParent():GetParent()
    local borderFrame = container.borderFrame
    local glow = container.glow

    SetCursor("INSPECT_CURSOR")

    if self.isCollected then
        borderFrame:SetBackdropBorderColor(1, 1, 1, 1)
        glow:SetColorTexture(1, 1, 1, 0.1)
    else
        borderFrame:SetBackdropBorderColor(1, 0.82, 0, 1)
        glow:SetColorTexture(1, 0.82, 0, 0.2)
    end

    if self.itemID then
        local itemName

        if C_Item and C_Item.GetItemNameByID then
            itemName = C_Item.GetItemNameByID(self.itemID)
        end

        if not itemName and GetItemInfo then
            itemName = GetItemInfo(self.itemID)
        end

        GameTooltip:SetOwner(self, "ANCHOR_LEFT")
        GameTooltip:ClearLines()

        GameTooltip:AddLine(itemName or ("Item ID: " .. tostring(self.itemID)), 0, 1, 0)

        if self.isCollected then
            GameTooltip:AddLine("Collected", 0.2, 1, 0.2)
        else
            GameTooltip:AddLine("Not collected", 1, 0.82, 0)
        end

        GameTooltip:AddLine(" ")
        GameTooltip:AddLine("Left-click to preview in DecorVendor", 0.65, 0.85, 1)
        GameTooltip:AddLine("Shift-click to open Blizzard preview", 0.75, 0.75, 0.75)

        GameTooltip:Show()
    end
end

function PopupButton_OnLeave(self)
    local container = self:GetParent():GetParent()
    local borderFrame = container.borderFrame
    local glow = container.glow

    ResetCursor()

    if self.isCollected then
        borderFrame:SetBackdropBorderColor(1, 1, 1, 1)
    else
        borderFrame:SetBackdropBorderColor(0.4, 0.4, 0.4, 1)
    end

    glow:SetColorTexture(0, 0, 0, 0.5)
    GameTooltip:Hide()
end

local function GetVendorPopupItemName(itemID)
    if not itemID then
        return nil
    end

    local itemName

    if C_Item and C_Item.GetItemNameByID then
        itemName = C_Item.GetItemNameByID(itemID)
    end

    if not itemName and GetItemInfo then
        itemName = GetItemInfo(itemID)
    end

    return itemName
end

local function PreviewVendorDecorItem(itemID)
    if not itemID then
        return
    end

    local sourceData =
        (dv.ActiveItems and dv.ActiveItems[itemID])
        or (dv.decorItem and dv.decorItem[itemID])

    if not sourceData then
        print("|cffffcc00DecorVendor:|r No preview data found for itemID " .. tostring(itemID))
        return
    end

    local itemData = {}

    for k, v in pairs(sourceData) do
        itemData[k] = v
    end

    itemData.id = itemData.id or itemID
    itemData.itemID = itemData.itemID or itemID

    local itemName = GetVendorPopupItemName(itemID) or sourceData.name or sourceData.title or ("Item " .. tostring(itemID))

    if dv.contentArea then
        dv.contentArea._isVendorPreview = false
    end

    if dv.ShowPreviewModel then
        dv.ShowPreviewModel(
            itemData.model3D or itemData.asset,
            itemName,
            itemData
        )
    else
        print("|cffff4040DecorVendor:|r dv.ShowPreviewModel is missing.")
    end
end

function PopupButton_OnClick(self, button)
    if not self.itemID then
        return
    end

    -- Shift-click keeps your old Blizzard decor/dressup preview behavior.
    if button == "LeftButton" and IsShiftKeyDown() then
        DressUpItemLink("item:" .. tostring(self.itemID))
        return
    end

    -- Normal left-click previews the decor inside your DecorVendor preview panel.
    if button == "LeftButton" then
        PreviewVendorDecorItem(self.itemID)
        return
    end
end

local function SetupPopupButton(container, itemID)
    local btn = container.btn
    local borderFrame = container.borderFrame

    container.itemID = itemID
    btn.itemID = itemID
    btn.isCollected = false

    if dv.catalogReady and dv.IsItemCollected then
        btn.isCollected = dv.IsItemCollected(itemID)
    end

    borderFrame:SetBackdropBorderColor(
        btn.isCollected and 1 or 0.4,
        btn.isCollected and 1 or 0.4,
        btn.isCollected and 1 or 0.4,
        1
    )

    if btn.isCollected and vendorSettings.showVendorCheckmarks then
        container.checkFrame:Show()
    else
        container.checkFrame:Hide()
    end

    local texture = GetItemIcon(itemID)
    container.icon:SetTexture(texture or "Interface\\Icons\\INV_Misc_QuestionMark")

    btn:SetScript("OnEnter", PopupButton_OnEnter)
    btn:SetScript("OnLeave", PopupButton_OnLeave)
    btn:SetScript("OnClick", PopupButton_OnClick)

    container:Show()
end

-------------------------------------------------
-- Dynamic Grid Layout
-------------------------------------------------

local function GetIconsPerRow()
    local width = vendorPopup.content:GetWidth()

    if not width or width <= 1 then
        width = (vendorPopup:GetWidth() or 300) - 20
    end

    local iconsPerRow = math.floor((width + ICON_GAP) / (ICON_SIZE + ICON_GAP))

    return math.max(1, math.min(6, iconsPerRow))
end

local function LayoutPopupItems(items)
    local totalItems = #items
    local columns = GetIconsPerRow()

    if totalItems <= 0 then
        return
    end

    for i, itemID in ipairs(items) do
        local container = GetPopupIconFrame(i)

        container:ClearAllPoints()

        local row = math.floor((i - 1) / columns)
        local col = (i - 1) % columns

        local iconsThisRow = math.min(totalItems - (row * columns), columns)
        local rowWidth = (iconsThisRow * ICON_SIZE) + ((iconsThisRow - 1) * ICON_GAP)

        local x = math.floor(((vendorPopup.content:GetWidth() or 280) - rowWidth) / 2)
        local y = -row * (ICON_SIZE + ICON_GAP + 8)

        container:SetPoint(
            "TOPLEFT",
            vendorPopup.content,
            "TOPLEFT",
            x + col * (ICON_SIZE + ICON_GAP),
            y
        )

        SetupPopupButton(container, itemID)
    end
end

UpdateVendorPopup = function()
    for _, iconFrame in pairs(popupIconCache) do
        iconFrame:Hide()
    end

    local totalItems = #vendorFilteredItems
    local totalPages = math.max(1, math.ceil(totalItems / ICONS_PER_PAGE))

    if currentVendorPage > totalPages then
        currentVendorPage = totalPages
    end

    local itemsToShow = {}
    local startIndex = (currentVendorPage - 1) * ICONS_PER_PAGE + 1
    local endIndex = math.min(startIndex + ICONS_PER_PAGE - 1, totalItems)

    for i = startIndex, endIndex do
        table.insert(itemsToShow, vendorFilteredItems[i])
    end

    LayoutPopupItems(itemsToShow)

    if dv.currentTab == "vendors" and totalPages > 1 then
        pagingFrame:Show()
        dv.vendorPrevBtn:Show()
        dv.vendorNextBtn:Show()
        dv.vendorPageText:Show()

        dv.vendorPageText:SetText(string.format("%d / %d", currentVendorPage, totalPages))
        dv.vendorPrevBtn:SetEnabled(currentVendorPage > 1)
        dv.vendorNextBtn:SetEnabled(currentVendorPage < totalPages)
    else
        pagingFrame:Hide()
        dv.vendorPrevBtn:Hide()
        dv.vendorNextBtn:Hide()
        dv.vendorPageText:Hide()
    end
end

-------------------------------------------------
-- Public Vendor Popup
-------------------------------------------------
local function LayoutVendorPreviewTitle(hasWaypointButton)
    if not dv.modelTitle or not dv.itemContainer then
        return
    end

    dv.modelTitle:ClearAllPoints()
    dv.modelTitle:SetPoint("TOPLEFT", dv.itemContainer, "TOPLEFT", 10, -10)

    if hasWaypointButton and dv.vendorWaypointBtn then
        dv.modelTitle:SetPoint("TOPRIGHT", dv.vendorWaypointBtn, "TOPLEFT", -8, 0)
    else
        dv.modelTitle:SetPoint("TOPRIGHT", dv.itemContainer, "TOPRIGHT", -10, -10)
    end

    dv.modelTitle:SetHeight(22)
    dv.modelTitle:SetJustifyH("CENTER")
    dv.modelTitle:SetWordWrap(false)
    dv.modelTitle:SetNonSpaceWrap(false)
end

function dv.ShowVendorPopup(vendorID, vendorName)
    if not vendorID then
        return
    end

    local vendor = dv.GetVendorInfo and dv.GetVendorInfo(vendorID)

    if not vendor then
        return
    end

    local vendorData = dv.vendorGoodies and dv.vendorGoodies[vendorID]

    currentPopupVendorID = vendorID
    currentPopupNpcName = vendorName or currentPopupNpcName
    dv.selectedVendor = vendor

    -------------------------------------------------
    -- Gather vendor items
    -------------------------------------------------

    local addedItems = {}

    if vendorData then
        if vendorData.items then
            for _, itemID in ipairs(vendorData.items) do
                table.insert(addedItems, itemID)
            end

        elseif type(vendorData) == "table" then
            for _, itemID in ipairs(vendorData) do
                if type(itemID) == "number" then
                    table.insert(addedItems, itemID)
                end
            end
        end
    end

    vendorFilteredItems = addedItems
    currentVendorPage = 1

    -------------------------------------------------
    -- Vendor zone/subtitle
    -------------------------------------------------

    if dv.vendorZoneText then
        if vendor.zone and vendor.zone ~= "" then
            dv.vendorZoneText:SetText(vendor.zone)
            dv.vendorZoneText:Show()
        else
            dv.vendorZoneText:SetText("")
            dv.vendorZoneText:Hide()
        end
    end

    -------------------------------------------------
    -- Waypoint Button
    -------------------------------------------------

    if not dv.vendorWaypointBtn then
        dv.vendorWaypointBtn = CreateFrame("Button", nil, dv.itemContainer, "UIPanelButtonTemplate")
        dv.vendorWaypointBtn:SetSize(76, 20)
        dv.vendorWaypointBtn:SetText("Waypoint")
    end

    local waypointBtn = dv.vendorWaypointBtn

    waypointBtn:ClearAllPoints()
    waypointBtn:SetPoint("TOPRIGHT", dv.itemContainer, "TOPRIGHT", -10, -10)

    if vendorSettings.showWaypointButton and vendor.mapID and vendor.x and vendor.y then
        waypointBtn:Show()

        waypointBtn:SetScript("OnClick", function()
            if hasTomTom and TomTom then
                TomTom:AddWaypoint(
                    vendor.mapID,
                    vendor.x / 100,
                    vendor.y / 100,
                    {
                        title = vendor.title .. " - " .. (vendor.zone or ""),
                        persistent = false,
                        minimap = true,
                        world = true,
                    }
                )
            end

            local vec = CreateVector2D(vendor.x / 100, vendor.y / 100)
            local mapPoint = UiMapPoint.CreateFromVector2D(vendor.mapID, vec)

            C_Map.SetUserWaypoint(mapPoint)
            C_SuperTrack.SetSuperTrackedUserWaypoint(true)

            PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON)
            print("|cff00ff00DecorVendor:|r Waypoint set for " .. vendor.title)
        end)
    else
        waypointBtn:Hide()
    end
	LayoutVendorPreviewTitle(waypointBtn:IsShown())
    -------------------------------------------------
    -- Build popup
    -------------------------------------------------

    UpdateVendorPopup()
    vendorPopup:Show()

    if C_HousingCatalog and C_HousingCatalog.RequestHousingMarketInfoRefresh then
        C_HousingCatalog.RequestHousingMarketInfoRefresh()
    end

    C_Timer.After(0.1, function()
        if vendorPopup:IsShown() then
            UpdateVendorPopup()
        end
    end)
end