-- ============================================================
-- Decor Vendor Gallery
-- FILE NAME HERE
-- Short description here
-- ============================================================

local addonName, Gallery = ...

Gallery.C = Gallery.C or {}
local C = Gallery.C
local CatSizing = C.CatalogSizing or {}


local DVD = _G.DecorVendorData or _G.DecorVendor_Data
Gallery.ActiveItems = DVD and DVD.ActiveItems or Gallery.ActiveItems or {}

-- Optional compatibility only
local dv = _G.DecorVendor or _G.Decorvendor
if dv then
    dv.Gallery = Gallery
end

function Gallery.CreatePreview(frame)
    local preview = CreateFrame("Frame", "DecorVendorGalleryPreview", frame, "BackdropTemplate")
    preview:SetWidth(CatSizing.DetailPanelWidth)
    preview:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -1, -33)
    preview:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -1, 15)
    preview:SetBackdrop({bgFile = "Interface\\Buttons\\WHITE8X8"})
    preview:SetBackdropColor(0.05, 0.05, 0.07, 1)

    frame.preview = preview

    preview.modelBox = CreateFrame("Frame", nil, preview)
    preview.modelBox:SetHeight(CatSizing.ModelViewerHeight)
    preview.modelBox:SetPoint("TOPLEFT", preview, "TOPLEFT", 4, -4)
    preview.modelBox:SetPoint("TOPRIGHT", preview, "TOPRIGHT", -4, -4)

    preview.modelBg = preview.modelBox:CreateTexture(nil, "BACKGROUND")
    preview.modelBg:SetAllPoints()
    preview.modelBg:SetAtlas("catalog-list-preview-bg")

    preview.modelScene = CreateFrame("ModelScene", nil, preview.modelBox, "PanningModelSceneMixinTemplate")
    preview.modelScene:SetPoint("TOPLEFT", 6, -6)
    preview.modelScene:SetPoint("BOTTOMRIGHT", -6, 6)
    preview.modelScene:EnableMouse(true)
    preview.modelScene:EnableMouseWheel(true)

    local dragLastX, dragLastY = nil, nil

    preview.modelScene:HookScript(
        "OnMouseDown",
        function(self, button)
            if button == "LeftButton" then
                dragLastX, dragLastY = GetCursorPosition()
            end
        end
    )

    preview.modelScene:HookScript(
        "OnMouseUp",
        function(self, button)
            if button == "LeftButton" then
                dragLastX, dragLastY = nil, nil
            end
        end
    )

    preview.modelScene:HookScript(
        "OnUpdate",
        function(self)
            if dragLastX and dragLastY then
                local x, y = GetCursorPosition()
                local dx = (x - dragLastX) * 0.02
                local dy = (y - dragLastY) * 0.02

                dragLastX, dragLastY = x, y

                local actor = self:GetActorByTag("decor")

                if actor then
                    actor:SetYaw((actor:GetYaw() or 0) + dx)
                    actor:SetPitch((actor:GetPitch() or 0) - dy)
                end
            end
        end
    )

    preview.controls = CreateFrame("Frame", nil, preview.modelBox, "ModelSceneControlFrameTemplate")
    preview.controls:SetPoint("BOTTOM", preview.modelBg, "BOTTOM", 0, 8)
    preview.controls:SetModelScene(preview.modelScene)

    preview.corbelLeft = preview.modelBox:CreateTexture(nil, "OVERLAY")
    preview.corbelLeft:SetAtlas("catalog-corbel-bottom-left")
    preview.corbelLeft:SetSize(66, 50)
    preview.corbelLeft:SetPoint("BOTTOMLEFT", preview.modelBox, "BOTTOMLEFT", 0, 0)

    preview.corbelRight = preview.modelBox:CreateTexture(nil, "OVERLAY")
    preview.corbelRight:SetAtlas("catalog-corbel-bottom-right")
    preview.corbelRight:SetSize(66, 50)
    preview.corbelRight:SetPoint("BOTTOMRIGHT", preview.modelBox, "BOTTOMRIGHT", 0, 0)

    -- Watermark / fallback icon
    preview.watermarkFrame = CreateFrame("Frame", nil, preview)
    preview.watermarkFrame:SetPoint("TOPLEFT", preview.modelBg, "TOPLEFT", 0, 0)
    preview.watermarkFrame:SetPoint("BOTTOMRIGHT", preview.modelBg, "BOTTOMRIGHT", 0, 0)
    preview.watermarkFrame:SetFrameStrata("HIGH")

    preview.watermark = preview.watermarkFrame:CreateTexture(nil, "ARTWORK")
    preview.watermark:SetSize(180, 180)
    preview.watermark:SetPoint("CENTER", preview.watermarkFrame, "CENTER", 0, 0)
    preview.watermark:SetTexture("Interface\\AddOns\\DecorVendor\\Assets\\decorvendoricon.tga")
    preview.watermark:SetAlpha(0.30)

    preview.watermarkFrame:Show()

    preview.name = preview:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    preview.name:SetPoint("TOP", preview.modelBox, "BOTTOM", 0, -12)
    preview.name:SetWidth(320)
    preview.name:SetHeight(38)
    preview.name:SetJustifyH("CENTER")
    preview.name:SetJustifyV("TOP")
    preview.name:SetWordWrap(true)

    preview.status = preview:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    preview.status:SetPoint("TOP", preview.name, "BOTTOM", 0, -4)
    preview.status:SetWidth(320)
    preview.status:SetHeight(18)
    preview.status:SetJustifyH("CENTER")
    preview.status:SetText("|cffaaaaaaNo Decor Selected|r")

    preview.statsText = preview:CreateFontString(nil, "OVERLAY", "GameFontHighlight")

    local statsText = preview.statsText

    statsText:SetPoint("TOP", preview.status, "BOTTOM", 0, -10)
    statsText:SetWidth(360)
    statsText:SetHeight(28)
    statsText:SetJustifyH("CENTER")
    statsText:SetJustifyV("MIDDLE")
    statsText:SetWordWrap(false)
    statsText:SetFont(STANDARD_TEXT_FONT, 13, "OUTLINE")
    statsText:SetTextColor(0.9, 0.9, 0.9)
    statsText:SetText("")

    preview.sourceHeader = preview:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    preview.sourceHeader:SetPoint("TOPLEFT", statsText, "BOTTOMLEFT", 28, -14)
    preview.sourceHeader:SetText("|cffffd100SOURCE|r")

    preview.sourceLine = preview:CreateTexture(nil, "ARTWORK")
    preview.sourceLine:SetColorTexture(0.85, 0.65, 0.2, 0.85)
    preview.sourceLine:SetPoint("TOPLEFT", preview.sourceHeader, "BOTTOMLEFT", 0, -4)
    preview.sourceLine:SetPoint("TOPRIGHT", preview, "TOPRIGHT", -16, 0)
    preview.sourceLine:SetHeight(1)

    preview.sourceText = preview:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    preview.sourceText:SetPoint("TOPLEFT", preview.sourceLine, "BOTTOMLEFT", 0, -10)
    preview.sourceText:SetWidth(320)
    preview.sourceText:SetJustifyH("LEFT")

    preview.requirementText = preview:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    preview.requirementText:SetPoint("TOPLEFT", preview.sourceText, "BOTTOMLEFT", 0, -12)
    preview.requirementText:SetWidth(320)
    preview.requirementText:SetJustifyH("LEFT")
    preview.requirementText:SetTextColor(1, 0.82, 0.2)
    preview.requirementText:SetText("")

    preview.noteText = preview:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    preview.noteText:SetPoint("TOPLEFT", preview.requirementText, "BOTTOMLEFT", 0, -10)
    preview.noteText:SetWidth(320)
    preview.noteText:SetJustifyH("LEFT")
    preview.noteText:SetTextColor(0.85, 0.78, 0.55)
    preview.noteText:SetText("")

    preview.actionButton = CreateFrame("Button", nil, preview, "UIPanelButtonTemplate")
    preview.actionButton:SetSize(CatSizing.DetailPanelWidth - 16, 26)
    preview.actionButton:SetPoint("BOTTOM", 0, 18)
    preview.actionButton:SetText("No Action")
    preview.actionButton:Disable()

    preview.sourceButton = CreateFrame("Button", nil, preview, "UIPanelButtonTemplate")
    preview.sourceButton:SetSize(CatSizing.DetailPanelWidth - 16, 24)
    preview.sourceButton:SetPoint("BOTTOM", preview.actionButton, "TOP", 0, 6)
    preview.sourceButton:SetText("Show Source Location")
    preview.sourceButton:Hide()

    preview.achievementButton = CreateFrame("Button", nil, preview, "UIPanelButtonTemplate")
    preview.achievementButton:SetSize(CatSizing.DetailPanelWidth - 16, 24)
    preview.achievementButton:SetPoint("BOTTOM", preview.sourceButton, "TOP", 0, 6)
    preview.achievementButton:SetText("Open Achievement")
    preview.achievementButton:Hide()
end


function Gallery.ShowPreviewModel(preview, item)
    if not preview or not item then return false end

    local itemData = item.data or {}
    local decorID = itemData.decorID or item.decorID
    local catalogInfo = Gallery.GetCatalogInfo and Gallery.GetCatalogInfo(decorID)

    local asset =
        (catalogInfo and catalogInfo.asset)
        or itemData.asset
        or itemData.model3D

    local sceneID =
        (catalogInfo and catalogInfo.uiModelSceneID)
        or itemData.uiModelSceneID
        or 859

    if not asset or asset == 0 then
        return false
    end

    local scene = preview.modelScene
    if not scene then return false end

    if preview.watermarkFrame then
    preview.watermarkFrame:Hide()
end
    scene:Show()

    if preview.controls then
        preview.controls:Show()
    end

    scene:ClearScene()

    pcall(function()
        scene:TransitionToModelSceneID(
            sceneID,
            CAMERA_TRANSITION_TYPE_IMMEDIATE,
            CAMERA_MODIFICATION_TYPE_DISCARD,
            true
        )
    end)

    local actor = scene:GetActorByTag("decor")

    if not actor and scene.CreateActor then
        actor = scene:CreateActor()

        if actor and actor.SetTag then
            actor:SetTag("decor")
        end
    end

    if not actor then
        scene:Hide()

        if preview.controls then
            preview.controls:Hide()
        end

        return false
    end

    actor:SetPreferModelCollisionBounds(true)
    actor:SetModelByFileID(asset)

    if actor.SetYaw then
        actor:SetYaw(0)
    end

    if actor.SetPitch then
        actor:SetPitch(0)
    end

    return true
end

function Gallery.UpdatePreviewDetails(item)
    local frame = Gallery.frame
    local preview = frame and frame.preview

    if not preview or not item then return end

    if preview.statsText then
        local statsText =
            (Gallery.BuildPreviewStatsText and Gallery.BuildPreviewStatsText(item))
            or ""

        preview.statsText:SetText(statsText)
    end
end

function Gallery.ShowItem(item)
    local frame = Gallery.frame
    local preview = frame and frame.preview

    if not preview or not item then return end

    local itemData = item.data or {}
    preview._currentItem = item

    -- ============================================================
    -- Name
    -- ============================================================
    local itemName =
        item.name
        or itemData.name
        or (Gallery.GetItemName and Gallery.GetItemName(item.itemID, itemData))
        or "Unknown Decor"

    preview.name:SetText("|cffffd100" .. itemName .. "|r")

    if string.len(itemName or "") > 34 then
        preview.name:SetFont(STANDARD_TEXT_FONT, 13, "")
    else
        preview.name:SetFont(STANDARD_TEXT_FONT, 15, "")
    end

    -- ============================================================
    -- Collection status
    -- ============================================================
    local collected =
        item.isCollected
        or (item.itemID and dv.IsItemCollected and dv.IsItemCollected(item.itemID))
        or false

    if collected then
        preview.status:SetText("|cff00ff00Collected|r")
    else
        preview.status:SetText("|cffff4040Not Collected|r")
    end

    -- ============================================================
    -- Model preview
    -- ============================================================
    local modelShown = Gallery.ShowPreviewModel and Gallery.ShowPreviewModel(preview, item)

    if modelShown then
        if preview.watermarkFrame then
            preview.watermarkFrame:Hide()
        end
    else
        if preview.modelScene then
            preview.modelScene:Hide()
        end

        if preview.controls then
            preview.controls:Hide()
        end

        if preview.watermarkFrame then
            preview.watermarkFrame:Show()
        end
    end


    -- ============================================================
    -- Requirement
    -- ============================================================
    local requirementText = nil
    local itemDetails =
        Gallery.GetItemDetailsForItem
        and Gallery.GetItemDetailsForItem(item)
        or {}

    local vendorDetails =
        Gallery.GetVendorDetailsForItem
        and Gallery.GetVendorDetailsForItem(item)

    local hasVendorDetails =
        itemData.soldBy
        or itemData.vendorID
        or (type(vendorDetails) == "table" and next(vendorDetails) ~= nil)

    -- Vendor requirements are already shown under SOURCE with the vendor.
    -- Do not show the separate Requirement block for vendor items.
    if not hasVendorDetails then
        local requirement =
            itemDetails.requirement
            or itemDetails.requires
            or itemData.requirement
            or itemData.requires

        if requirement and Gallery.FormatRequirement then
            requirementText = Gallery.FormatRequirement(requirement)
        elseif type(requirement) == "string" then
            requirementText = requirement
        end
    end

    if preview.requirementText then
        if requirementText and requirementText ~= "" then
            preview.requirementText:SetText("|cffffd100Requirement:|r\n" .. requirementText)
            preview.requirementText:Show()
        else
            preview.requirementText:SetText("")
            preview.requirementText:Hide()
        end
    end

    -- ============================================================
    -- Note
    -- ============================================================
    if itemData.note then
        preview.noteText:SetText("|cffffd100Note:|r\n" .. tostring(itemData.note))
    else
        preview.noteText:SetText("")
    end

    -- ============================================================
    -- Extra preview details
    -- Important: this may update stats/detail widgets.
    -- If it also touches sourceText, we overwrite sourceText below.
    -- ============================================================
    if Gallery.UpdatePreviewDetails then
        Gallery.UpdatePreviewDetails(item)
    end

    -- ============================================================
    -- Source/details text
    -- This should show source + achievement + quest + boss/treasure + vendors.
    -- ============================================================
local sourceText

if Gallery.BuildPreviewSourceText then
    sourceText = Gallery.BuildPreviewSourceText(item)
elseif Gallery.GetSourceTextForItem then
    sourceText = Gallery.GetSourceTextForItem(item)
else
    sourceText = "Unknown"
end

preview.sourceText:SetText(sourceText or "Unknown")
    preview.sourceText:SetTextColor(1, 1, 1, 1)

    -- Fallback: if BuildPreviewSourceText is missing, preserve the old append behavior.
    if not Gallery.BuildPreviewSourceText then
        local achievementText = Gallery.GetAchievementSourceText and Gallery.GetAchievementSourceText(item)

        if achievementText then
            sourceText = sourceText .. "\n\n" .. achievementText
        end

        local vendors = Gallery.GetVendorNamesFromItem and Gallery.GetVendorNamesFromItem(itemData)

        if vendors then
            sourceText = sourceText .. "\n\n|cff80ff80Sold by:|r " .. vendors
        end

        if itemData.questName then
            sourceText = sourceText .. "\n|cff80ff80Quest:|r " .. itemData.questName
        elseif itemData.questID then
            sourceText = sourceText .. "\n|cff80ff80Quest ID:|r " .. tostring(itemData.questID)
        end

        if itemData.bossName then
            sourceText = sourceText .. "\n|cff80ff80Boss:|r " .. itemData.bossName
        elseif itemData.bossevent then
            sourceText = sourceText .. "\n|cff80ff80Event:|r " .. tostring(itemData.bossevent)
        elseif itemData.bossencounter then
            sourceText = sourceText .. "\n|cff80ff80Boss Encounter:|r " .. tostring(itemData.bossencounter)
        end

        if itemData.profession then
            sourceText = sourceText .. "\n|cff80ff80Profession:|r " .. tostring(itemData.profession)
        end
    end


    -- ============================================================
    -- Buttons
    -- ============================================================
    if Gallery.UpdateActionButton then
        Gallery.UpdateActionButton(item)
    end

    if Gallery.UpdateAchievementButton then
        Gallery.UpdateAchievementButton(item)
    end
end

function Gallery.UpdateActionButton(item)
    local frame = Gallery.frame
    local preview = frame and frame.preview

    if not preview or not preview.actionButton then
        return
    end

    -------------------------------------------------
    -- Reset buttons first
    -------------------------------------------------

    preview.actionButton:SetScript("OnClick", nil)
    preview.actionButton:Disable()
    preview.actionButton:SetAlpha(0.55)
    preview.actionButton:SetText("No Action")

    if preview.sourceButton then
        preview.sourceButton:SetScript("OnClick", nil)
        preview.sourceButton:Disable()
        preview.sourceButton:SetAlpha(0.55)
        preview.sourceButton:SetText("Show Source Location")
        preview.sourceButton:Hide()
    end

    if preview.achievementButton then
        preview.achievementButton:SetScript("OnClick", nil)
        preview.achievementButton:Disable()
        preview.achievementButton:SetAlpha(0.55)
        preview.achievementButton:SetText("Open Achievement")
        preview.achievementButton:Hide()
    end

    if not item then
        return
    end

    local itemData = item.data or {}

    local function NormalizeSource(value)
        if Gallery.NormalizeSource then
            return Gallery.NormalizeSource(value)
        end

        return string.lower(tostring(value or ""))
    end

    local function HasSource(sourceKey)
        sourceKey = NormalizeSource(sourceKey)

        if Gallery.ItemHasSource and Gallery.ItemHasSource(item, sourceKey) then
            return true
        end

        if NormalizeSource(item.source) == sourceKey then
            return true
        end

        if NormalizeSource(item.sourceType) == sourceKey then
            return true
        end

        if NormalizeSource(itemData.source) == sourceKey then
            return true
        end

        if NormalizeSource(itemData.sourceType) == sourceKey then
            return true
        end

        local sources =
            item.sources
            or item.sourceTypes
            or itemData.sources
            or itemData.sourceTypes

        if type(sources) == "table" then
            for key, value in pairs(sources) do
                if value == true and NormalizeSource(key) == sourceKey then
                    return true
                end

                if NormalizeSource(value) == sourceKey then
                    return true
                end
            end
        end

        return false
    end

    -------------------------------------------------
    -- Gather possible actions once
    -------------------------------------------------

    local specialAction =
        Gallery.GetSpecialActionForItem
        and Gallery.GetSpecialActionForItem(item)

    local achievementInfo =
        Gallery.GetAchievementForItem
        and Gallery.GetAchievementForItem(item)

    local bestVendor =
        Gallery.GetBestFactionVendorForItem
        and Gallery.GetBestFactionVendorForItem(item)

    local vendors =
        Gallery.GetVendorsForItem
        and Gallery.GetVendorsForItem(item)
        or {}

    local hasVendorPath = bestVendor or #vendors > 0
    local hasShopPath = HasSource("shop")

    -------------------------------------------------
    -- Achievement secondary button
    -- Can show alongside vendor/shop/source buttons.
    -------------------------------------------------

    if achievementInfo and achievementInfo.id and preview.achievementButton then
        preview.achievementButton:SetText("Open Achievement")
        preview.achievementButton:Show()
        preview.achievementButton:Enable()
        preview.achievementButton:SetAlpha(1)

        preview.achievementButton:SetScript("OnClick", function()
            if Gallery.OpenAchievementByID then
                Gallery.OpenAchievementByID(achievementInfo.id)
                return
            end

            if AchievementFrame_LoadUI then
                AchievementFrame_LoadUI()
            end

            if AchievementFrame_ToggleAchievementFrame then
                AchievementFrame_ToggleAchievementFrame()
            end

            if AchievementFrame_SelectAchievement then
                AchievementFrame_SelectAchievement(achievementInfo.id)
            end
        end)
    end

    -------------------------------------------------
    -- Source/location secondary button
    -- Shows when the main button is used by shop/vendor.
    -------------------------------------------------

    if specialAction and preview.sourceButton and (hasVendorPath or hasShopPath) then
        if specialAction.type == "journal" then
            preview.sourceButton:SetText("Open Source Journal")

        elseif specialAction.type == "map" then
            local count = specialAction.locations and #specialAction.locations or 0

            if count > 1 then
                preview.sourceButton:SetText("Pin Source Locations")
            else
                preview.sourceButton:SetText("Show Source Location")
            end

        elseif specialAction.type == "worldmap" then
            preview.sourceButton:SetText("Open Source Map")

        else
            preview.sourceButton:SetText("Open Source")
        end

        preview.sourceButton:Show()
        preview.sourceButton:Enable()
        preview.sourceButton:SetAlpha(1)

        preview.sourceButton:SetScript("OnClick", function()
            if Gallery.RunSpecialItemAction then
                Gallery.RunSpecialItemAction(item)
            end
        end)
    end

    -------------------------------------------------
    -- In-Game Shop
    -- Highest priority for shop items.
    -------------------------------------------------

    if hasShopPath then
        preview.actionButton:SetText("Open In-Game Shop")
        preview.actionButton:Enable()
        preview.actionButton:SetAlpha(1)

        preview.actionButton:SetScript("OnClick", function()
            if C_AddOns and C_AddOns.LoadAddOn then
                pcall(C_AddOns.LoadAddOn, "Blizzard_StoreUI")
            end

            if ToggleStoreUI then
                ToggleStoreUI()
            else
                print("|cffff4040Decor Vendor Gallery:|r The in-game shop UI is not available right now.")
            end
        end)

        return
    end

    -------------------------------------------------
    -- Vendor navigation
    -------------------------------------------------

    if bestVendor then
        preview.actionButton:SetText("Navigate (" .. (bestVendor.title or bestVendor.name or "Vendor") .. ")")
        preview.actionButton:Enable()
        preview.actionButton:SetAlpha(1)

        preview.actionButton:SetScript("OnClick", function()
            if Gallery.SetWaypointToVendor then
                local itemName =
                    Gallery.GetItemName
                    and Gallery.GetItemName(item.itemID, item.data)
                    or item.name
                    or itemData.name
                    or "Decor"

                Gallery.SetWaypointToVendor(bestVendor, itemName)
            end
        end)

        return
    end

    -------------------------------------------------
    -- Vendors exist, but no usable direct coords
    -------------------------------------------------

    if #vendors > 0 then
        preview.actionButton:SetText("Location Varies")
        preview.actionButton:Disable()
        preview.actionButton:SetAlpha(0.55)
        return
    end

    -------------------------------------------------
    -- Special source action as main button
    -- Used when there is no vendor/shop main button.
    -------------------------------------------------

    if specialAction then
        if specialAction.type == "journal" then
            preview.actionButton:SetText("Open Encounter Journal")

        elseif specialAction.type == "map" then
            local count = specialAction.locations and #specialAction.locations or 0

            if count > 1 then
                preview.actionButton:SetText("Pin Locations")
            else
                preview.actionButton:SetText("Show Location")
            end

        elseif specialAction.type == "worldmap" then
            preview.actionButton:SetText("Open Map")

        else
            preview.actionButton:SetText("Open Source")
        end

        preview.actionButton:Enable()
        preview.actionButton:SetAlpha(1)

        preview.actionButton:SetScript("OnClick", function()
            if Gallery.RunSpecialItemAction then
                Gallery.RunSpecialItemAction(item)
            end
        end)

        return
    end

    -------------------------------------------------
    -- Achievement fallback as main button
    -------------------------------------------------

    local achievementID =
        itemData.achievementID
        or item.achievementID
        or itemData.vendorUnlockAchievementID
        or item.vendorUnlockAchievementID
        or (achievementInfo and achievementInfo.id)

    if achievementID then
        preview.actionButton:SetText("Open Achievement")
        preview.actionButton:Enable()
        preview.actionButton:SetAlpha(1)

        preview.actionButton:SetScript("OnClick", function()
            if Gallery.OpenAchievementByID then
                Gallery.OpenAchievementByID(achievementID)
                return
            end

            if AchievementFrame_LoadUI then
                AchievementFrame_LoadUI()
            end

            if AchievementFrame_ToggleAchievementFrame then
                AchievementFrame_ToggleAchievementFrame()
            end

            if AchievementFrame_SelectAchievement then
                AchievementFrame_SelectAchievement(achievementID)
            end
        end)

        return
    end
end