-- VDS_Rows_GalleryTile
-- ============================================================================
-- Row factory for `kind = "loadout"` in the liveWithGallery variants gallery.
-- Donor: VDS_Components.lua:573-715. 110x110 ModelScene tile (scrollbox owns
-- wheel, tile owns clicks) + hover-only delete X.
-- DecorInfoResolver supplies asset + uiModelSceneID; actor:SetGradientMaskWithDyes
-- applies the saved dye triple.

VDS = VDS or {}

local WHITE = "Interface\\Buttons\\WHITE8x8"
local DEFAULT_GALLERY_SCENE_ID = 691  -- HOUSING_CATALOG_DECOR_MODELSCENEID_DEFAULT

local function galleryDefaultSceneID()
    local C = _G.Constants
    return (C and C.HousingCatalogConsts  -- exception(boundary): Blizzard Constants table varies by patch
            and C.HousingCatalogConsts.HOUSING_CATALOG_DECOR_MODELSCENEID_DEFAULT)
        or DEFAULT_GALLERY_SCENE_ID
end

local function buildGalleryTile(row)
    row:SetHeight(110)

    local bg = row:CreateTexture(nil, "BACKGROUND")
    bg:SetPoint("TOPLEFT",     row, "TOPLEFT",     4, -4)
    bg:SetPoint("BOTTOMRIGHT", row, "BOTTOMRIGHT", -4, 4)
    bg:SetTexture(WHITE)
    bg:SetVertexColor(0.05, 0.05, 0.07, 0.95)
    row._tile = bg

    -- Mouse interactions stripped so scrollbox owns wheel, row owns clicks (donor parity).
    local mscene = _G.CreateFrame("ModelScene", nil, row, "PanningModelSceneMixinTemplate")
    mscene:SetPoint("TOPLEFT",     bg, "TOPLEFT",     2, -2)
    mscene:SetPoint("BOTTOMRIGHT", bg, "BOTTOMRIGHT", -2, 2)
    mscene:EnableMouse(false)
    mscene:EnableMouseWheel(false)
    mscene:SetScript("OnMouseDown",  nil)
    mscene:SetScript("OnMouseUp",    nil)
    mscene:SetScript("OnMouseWheel", nil)
    mscene:SetScript("OnUpdate",     nil)
    mscene:Hide()
    row._mscene = mscene

    local hl = row:CreateTexture(nil, "HIGHLIGHT")
    hl:SetAllPoints(bg)
    hl:SetTexture(WHITE)
    hl:SetVertexColor(1, 1, 1, 0.10)

    -- 3 dye droplets (mirrors HousingDashboardFrame DyeDisplay), tinted to channel swatches.
    row._droplets = {}
    for i = 1, 3 do
        local d = row:CreateTexture(nil, "OVERLAY", nil, 1)
        d:SetSize(14, 14)
        if d.SetAtlas then d:SetAtlas(VDS.Constants.ATLAS.DYE_DROP) end
        d:Hide()
        row._droplets[i] = d
    end

    local label = row:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    label:SetPoint("BOTTOMLEFT",  bg, "BOTTOMLEFT",   4, 4)
    label:SetPoint("BOTTOMRIGHT", bg, "BOTTOMRIGHT", -4, 4)
    label:SetJustifyH("CENTER")
    label:SetWordWrap(false)
    label:SetTextColor(0.92, 0.93, 0.95, 1)
    label:SetShadowColor(0, 0, 0, 1)
    label:SetShadowOffset(1, -1)
    row._label = label

    local del = _G.CreateFrame("Button", nil, row)
    del:SetSize(18, 18)
    del:SetPoint("TOPRIGHT", bg, "TOPRIGHT", -2, -2)
    del:SetFrameLevel(row:GetFrameLevel() + 5)
    local delIcon = del:CreateTexture(nil, "ARTWORK")
    delIcon:SetAllPoints()
    delIcon:SetAtlas("common-icon-delete")
    del:Hide()
    row._del = del

    local function showX() del:Show() end
    local function hideX()
        if not row:IsMouseOver() and not del:IsMouseOver() then del:Hide() end
    end
    row:HookScript("OnEnter", showX)
    row:HookScript("OnLeave", hideX)
    del:HookScript("OnEnter", showX)
    del:HookScript("OnLeave", hideX)
    del:SetScript("OnClick", function()
        VDS.Controller_Live:OnGalleryTileDelete(row._decorID, row._idx)
    end)

    row:RegisterForClicks("AnyUp")
    row:SetScript("OnClick", function(self)
        VDS.Controller_Live:OnGalleryTileClick(self)
    end)
end

local function resetGalleryTile(row)
    if row._label  then row._label:SetText("") end
    if row._del    then row._del:Hide() end
    if row._mscene then row._mscene:Hide() end
    if row._droplets then
        for i = 1, 3 do row._droplets[i]:Hide() end
    end
    row._loadout = nil
    row._decorID = nil
    row._idx     = nil
    row._actor   = nil
end

local function initGalleryTile(row, data)
    row._loadout = data
    row._decorID = data.decorID
    row._idx     = data.idx
    if row._label then
        row._label:SetText(data.name or "Loadout")
    end

    if not data.decorID then
        row._mscene:Hide()
        return
    end

    local info = VDS.DecorInfoResolver:Resolve(data.decorID)  -- nil while catalog primes
    if not (info and info.asset) then  -- exception(nullable): resolver returns nil/partial pre-CATALOG_READY
        row._mscene:Hide()
        return
    end

    local sceneID = info.uiModelSceneID or galleryDefaultSceneID()
    row._mscene:TransitionToModelSceneID(sceneID,
        _G.CAMERA_TRANSITION_TYPE_IMMEDIATE,
        _G.CAMERA_MODIFICATION_TYPE_DISCARD, true)

    local actor = row._mscene:GetActorByTag("decor")
    if actor then
        actor:SetPreferModelCollisionBounds(true)
        actor:SetModelByFileID(info.asset)
        if actor.SetGradientMaskWithDyes and data.dyes then
            actor:SetGradientMaskWithDyes(data.dyes[0], data.dyes[1], data.dyes[2])
        end
        row._actor = actor
    end
    row._mscene:Show()

    -- Droplets: data.dyes[0..2]; only show channels with a non-zero dyeID.
    local present = {}
    if data.dyes then
        for ch = 0, 2 do
            local id = data.dyes[ch]
            if id and id > 0 then present[#present + 1] = id end
        end
    end
    local nDots  = #present
    local size   = 14
    local gap    = 3
    local stride = size + gap
    local startX = -((nDots - 1) * stride) / 2
    for i = 1, 3 do
        local d = row._droplets[i]
        local id = present[i]
        if id then
            d:ClearAllPoints()
            d:SetPoint("BOTTOM", row._label, "TOP", startX + (i - 1) * stride, 2)
            local info2 = VDS.DyeOwnershipObserver:ResolveInfo(id)
            local c = info2 and info2.swatchRGB  -- exception(nullable): catalog lookup can miss pre-CATALOG_READY
            if c then d:SetVertexColor(c.r, c.g, c.b, 1) end
            d:Show()
        else
            d:Hide()
        end
    end
end

VDS.RowRegistry:Register("galleryTile", {
    build = buildGalleryTile,
    init  = initGalleryTile,
    reset = resetGalleryTile,
})
